在我正在处理的脚本的新添加中,我想循环遍历与标志关联的参数,直到 zsh 到达命令中的下一个标志。例如,当用户输入以下内容时:
datt -p Package1 Package2 Package3 --build
该脚本应采用Package1
、Package2
和Package3
并将它们分别分配到数组中的某个位置。我的思考过程是做类似的事情:
packages=()
for i in "$@"; do
packages+=("$i")
done
那么,我的问题是,如何编写脚本,使该循环一直持续下去,直到遇到命令行上的下一个标志?使用问题 ( ) 开头显示的命令datt -p Package1 Package2 Package3 --build
,如何防止 for 循环捕获--build
为包名称并使其停止向数组添加字符串PackageN
?
答案1
正确地进行参数解析可能会很烦人。我建议你使用获取选择(1)。从这里您可以多次指定相同的标志:
datt -p Package1 -p Package2 -p Package3 --build
如果由于某种原因你不能重用该标志(不确定那是什么,但是......)你也可以将参数作为单个项目传递并在空格上中断:
datt -p "Package1 Package2 Package3" --build
答案2
要进行这种解析,使用 while 循环更容易,shift
直到数组为空。
packages=()
while (($#)); do
case $1 in
-p)
while shift; [[ $1 != -* ]]; do
packages+=($1)
done
…
esac
shift
done
您可以使用i
下标标志执行内部循环,为您寻找下一个选项。$array[(i)PATTERN]
是第一个匹配 的元素的索引PATTERN
,索引从 1 开始,因此减去 1 即可得到剩下的元素数。如果 没有匹配PATTERN
,则该值是最后一个元素的索引加一,因此这样的代码在这种情况下也可以工作。
packages=()
while (($#)); do
case $1 in
-p) ((n = $@[(i)-*] - 1)); packages+=($@[1,$n]); shift $n;;
…
esac
shift
done
您描述的语法是非标准的。出于这个原因,我建议不要这样做:它可能会让您的用户感到困惑。通常datt -p Package1 Package2 Package3 --build
会做同样的事情datt -p Package1 Package2 --build Package3
。
答案3
通常,最明智的做法是在一个循环中遍历所有选项,并将内容放在正确的位置。通常,我不会从参数解析循环进行处理,但如果选项的顺序很重要,这可能是有意义的。
例如这样的循环(对于 Bash 或 zsh):
#!/usr/bin/zsh
packages=()
while [ "$#" -gt 0 ]; do
case $1 in
-p) echo "p option seen...";;
--build) echo "--build option seen after ${#packages[@]} packages...";;
*) echo "adding package '$1'";
packages+=("$1");;
esac
shift;
done
typeset -p packages;
会给出:
$ zsh dattest.sh -p foo bar doo --build
p option seen...
adding package 'foo'
adding package 'bar'
adding package 'doo'
--build option seen after 3 packages...
typeset -a packages=( foo bar doo )