循环遍历命令行参数选项直到下一个参数

循环遍历命令行参数选项直到下一个参数

在我正在处理的脚本的新添加中,我想循环遍历与标志关联的参数,直到 zsh 到达命令中的下一个标志。例如,当用户输入以下内容时:

datt -p Package1 Package2 Package3 --build

该脚本应采用Package1Package2Package3并将它们分别分配到数组中的某个位置。我的思考过程是做类似的事情:

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 )

相关内容