将命令行参数转换为 Bash 中的数组

Posted

技术标签:

【中文标题】将命令行参数转换为 Bash 中的数组【英文标题】:Convert command line arguments into an array in Bash 【发布时间】:2012-09-24 13:48:36 【问题描述】:

如何将命令行参数转换为 bash 脚本数组?

我想拿这个:

./something.sh arg1 arg2 arg3

并将其转换为

myArray=( arg1 arg2 arg3 )

这样我就可以在脚本中进一步使用 myArray。

这篇之前的 SO 帖子很接近,但没有涉及如何创建数组:How do I parse command line arguments in Bash?

我需要将参数转换为常规的 bash 脚本数组;我意识到我可以使用其他语言(例如 Python),但需要在 bash 中执行此操作。我想我正在寻找“附加”功能或类似的东西?

更新:我还想问如何检查零参数并分配默认数组值,并且感谢下面的答案,能够让它工作:

if [ "$#" -eq 0 ]; then
  myArray=( defaultarg1 defaultarg2 )
else
  myArray=( "$@" )
fi

【问题讨论】:

【参考方案1】:

实际上,您的命令行参数实际上已经像一个数组了。至少,您可以像对待数组一样对待$@ 变量。也就是说,你可以像这样将它转换成一个实际的数组:

myArray=( "$@" )

如果您只想输入一些参数并将它们输入$@ 值,请使用set

$ set -- apple banana "kiwi fruit"
$ echo "$#"
3
$ echo "$@"
apple banana kiwi fruit

了解如何使用参数结构在 POSIX sh 中特别有用,它没有其他任何东西像数组。

【讨论】:

谢谢!效果很好!正要问如何检查零参数并分配默认数组值,而 $# 非常适合! set 允许您设置范围的位置参数。它还允许您设置 shell 选项。您可以执行set foo,这意味着$1 扩展为“foo”,但如果您的参数以破折号开头,set 将假定您的意思是设置一个shell 选项。双破折号确保以下所有参数都被解释为要设置的位置参数。 一个陷阱:echo $@ 将打印所有参数,但echo $myArray 将仅打印第一个元素。要查看所有内容,请使用echo $myArray[@] @z0r 如果你不在这些扩展周围加上双引号,那么 bash 会重新分词,并可能失去意义。 对,“拼凑”一个数组并使用每个元素的一般方法是"$myArray[@]"。如果要遍历数组,则需要引号以避免在 IFS 上拆分其各个元素【参考方案2】:

也许这会有所帮助:

myArray=("$@") 

你也可以通过省略'in'来迭代参数:

for arg; do
   echo "$arg"
done

等价

for arg in "$myArray[@]"; do
   echo "$arg"
done

【讨论】:

新手问题:bash 如何知道将什么放入 arg 字段 - 它是预定义的变量吗? $var 扩展为var 的内容。 $var[n] 扩展为数组var 的元素n 的内容。是$var[@] 然后扩展整个数组,即$var[0] $var[1] ... $var[n]n是最后一个元素的索引)? [for] 没有 [in] 将遍历参数数组 $@($1、$2 等)。也可以使用 [set] 命令设置,例如 set -- arg1 arg2【参考方案3】:

这是另一种用法:

#!/bin/bash
array=( "$@" )
arraylength=$#array[@]
for (( i=0; i<$arraylength; i++ ));
do
   echo "$array[$i]"
done

【讨论】:

【参考方案4】:

实际上参数列表可以通过$1 $2 ...等访问。 这完全等同于:

$!i

因此,参数列表可以通过 set 进行更改, 而$!i 是访问它们的正确方法:

$ set -- aa bb cc dd 55 ff gg hh ii jjj kkk lll
$ for ((i=0;i<=$#;i++)); do echo "$#" "$i" "$!i"; done
12 1 aa
12 2 bb
12 3 cc
12 4 dd
12 5 55
12 6 ff
12 7 gg
12 8 hh
12 9 ii
12 10 jjj
12 11 kkk
12 12 lll

对于您的具体情况,可以使用它(不需要数组)在没有给出参数列表时设置参数列表:

if [ "$#" -eq 0 ]; then
    set -- defaultarg1 defaultarg2
fi

翻译成这个更简单的表达式:

[ "$#" == "0" ] && set -- defaultarg1 defaultarg2

【讨论】:

回显示例不应该是:echo "$#" "$i+1" "$!i"; 以获得完全如图所示的输出吗?【参考方案5】:

更简单,您可以直接在$@ 上操作;)

以下是如何直接从提示符传递参数列表:

function echoarg  for stuff in "$@" ; do echo $stuff ; done ;  
    echoarg Hey Ho Lets Go
    Hey
    Ho
    Lets
    Go

【讨论】:

更简单,for stuff in "$@" ; do ...for stuff ; do ... 相同 :)【参考方案6】:

数组和 $@ 几乎相同的并排视图。

代码:

#!/bin/bash

echo "Dollar-1 : $1"
echo "Dollar-2 : $2"
echo "Dollar-3 : $3"
echo "Dollar-AT: $@"
echo ""

myArray=( "$@" )

echo "A Val 0: $myArray[0]"
echo "A Val 1: $myArray[1]"
echo "A Val 2: $myArray[2]"
echo "A All Values: $myArray[@]"

输入:

./bash-array-practice.sh 1 2 3 4

输出:

Dollar-1 : 1
Dollar-2 : 2
Dollar-3 : 3
Dollar-AT: 1 2 3 4

A Val 0: 1
A Val 1: 2
A Val 2: 3
A All Values: 1 2 3 4

【讨论】:

【参考方案7】:

双引号的重要性值得强调。假设一个参数包含空格。

代码:

#!/bin/bash
printf 'arguments:%s\n' "$@"
declare -a arrayGOOD=( "$@" )
declare -a arrayBAAD=(  $@  )

printf '\n%s:\n' arrayGOOD
declare -p arrayGOOD
arrayGOODlength=$#arrayGOOD[@]
for (( i=1; i<$arrayGOODlength+1; i++ ));
do
   echo "$arrayGOOD[$i-1]"
done

printf '\n%s:\n' arrayBAAD
declare -p arrayBAAD
arrayBAADlength=$#arrayBAAD[@]
for (( i=1; i<$arrayBAADlength+1; i++ ));
do
   echo "$arrayBAAD[$i-1]"
done

输出:

> ./bash-array-practice.sh 'The dog ate the "flea" -- and ' the mouse.
arguments:The dog ate the "flea" -- and 
arguments:the
arguments:mouse.

arrayGOOD:
declare -a arrayGOOD='([0]="The dog ate the \"flea\" -- and " [1]="the" [2]="mouse.")'
The dog ate the "flea" -- and 
the
mouse.

arrayBAAD:
declare -a arrayBAAD='([0]="The" [1]="dog" [2]="ate" [3]="the" [4]="\"flea\"" [5]="--" [6]="and" [7]="the" [8]="mouse.")'
The
dog
ate
the
"flea"
--
and
the
mouse.
> 

【讨论】:

以上是关于将命令行参数转换为 Bash 中的数组的主要内容,如果未能解决你的问题,请参考以下文章

将命令行参数转换为字符串

自动完成命令行参数

如何从 Bash 中的文件调用多个命令行参数?

从命令行参数 C 将十六进制转换为二进制

如何转义变量中的特殊字符以在 bash 中提供命令行参数

Bash 中的命令行参数 [重复]