我想创建一个可以按如下方式执行的bash脚本:
bash myscript.sh -n n -k k -p1 p1 -p2 p2
其中n,k,p1,p2
是一些参数,-n, -k, -p1, -p2
指示指定了哪些参数。我希望能够解析它们。显而易见的解决方案是使用getopt
,这是行不通的,因为有一些选项的名称由多个字符组成。像这样迭代$@
变量:
for op in $@ ...
也不好,因为我无法访问邻居。有没有办法"正常"遍历列表,像这样?
for i in {1..$@}; do
case ${$i} in
-n) # do something, accessing ${i+1}
...
esac
done
您可以在处理选项后使用shift
删除选项。
while (($# > 0)); do
case $1 in
-n) use $2; shift 2;;
-k) use $2; shift 2;;
-p1) use $2; shift 2;;
-p2) use $2; shift 2;;
*) echo "Unrecognized option $1" >&2; exit 1;;
esac
done
John Kugelman 的有用答案是要走的路,但只是为了展示如何通过基于数组索引的访问来完成它$@
,输入参数的(伪)数组,涉及 shell 算术:
for (( i = 1; i <= $#; i+=2 )); do
this=${!i} # get argument with (1-based) index i; same as: ${@:i:1}
next=${@:i+1:1} # get argument i + 1
case $this in
-n) echo "$this value: [$next]";;
-k) echo "$this value: [$next]";;
-p1) echo "$this value: [$next]";;
-p2) echo "$this value: [$next]";;
*) echo "Unrecognized option: $this" >&2; exit 1;;
esac
done
请注意,此代码段做出了以下假设,这使得它不适合大多数实际用途:
- 脚本仅支持选项,不支持操作数(非选项参数)。
- 所有选项都需要一个选项参数,并且必须用空格将其与选项分隔开。
至于你尝试过的:
{1..$@}
您可能的意思是{1..$#}
为了枚举所有索引($#
是输入参数的计数),但是,这也不起作用,因为不幸的是,大括号扩展仅适用于文字值。有解决方法,但它们并不漂亮。
请注意,从 Bash 数组获取索引列表的常用方法不适用于伪数组$@
:
${!@}
生成空字符串而首先将
$@
复制到真正的数组确实有效:args=( "$@" ); echo "${!args[@]}"
在这种情况下,最好的解决方案是使用上面演示的 C 样式for
循环。
${$i}
尝试访问i
-th 参数在 Bash 中语法无效;然而,起作用的是使用变量间接:谢谢,rici
例如,$i
等于2
时,${!i}
等价于$2
。
但是,此语法不适用于计算索引(除非您笨拙地定义其他变量,例如iPlus1=$(( i + 1 ))
然后使用${!iPlus1}
)。
然而,幸运的是,当涉及到基于索引的元素访问时,$@
的行为确实像常规的 Bash 数组(除了第一个元素有索引1
,而不是0
):
因此,
${!i}
等价于${@:i:1}
,它返回索引$i
的 (1
) 元素 - 请注意,在索引规范中引用$i
时,我没有使用$
前缀前缀,因为它是在算术上下文中计算的,其中$
前缀变量引用是可选的,并且可以执行简单的整数计算。这允许基于计算索引的元素访问:具有索引
$i + 1
的元素可以使用${@:i+1:1}
访问。