【问题标题】:How do I make an option accept an arbitrary number of arguments如何使选项接受任意数量的参数
【发布时间】:2018-11-04 03:22:10
【问题描述】:

我正在尝试编写一个 shell 脚本,其中的选项在每次运行中采用不同数量的值,例如

运行 1:

./myscript --input <file1> <file2> --output <folder1>

运行 2:

./myscript --input <file1> <file2> <file3> --output <folder1> <folder2>

我尝试如下使用 getopts:

while getopts ":i:o:" opt; do
  case $opt in
  i)
    echo "treatment files are: $OPTARG" >&2
    infiles="${OPTARG}"
  ;;
  o)
    echo "control files are: $OPTARG" >&2
    outdir="${OPTARG}"
  ;;
  \?)
    echo "Invalid option: -$OPTARG" >&2
    exit 1
  ;;
  :)
    echo "Option -$OPTARG requires an argument." >&2
    exit 1
  ;;
  esac
done

但是,我发现为“-i”选项输入可变数量的值的唯一方法是通过引号(“file1 file2”),这会阻止我/用户使用命令行的自动完成功能来提供帮助生成文件路径。此外,此选项似乎不允许我使用“--input”语法来传递选项。

有人可以帮忙吗?

非常感谢。

【问题讨论】:

标签: shell


【解决方案1】:

您有两个问题。其中之一是“如何在我的 shell 脚本中实现长选项?”,对此有很好的阅读 here

另一个问题是,“如何让选项接受任意数量的参数?”答案大多是“你不知道”。通常最干净的解决方案是让您的脚本多次接受该选项,如下所示:

./myscript -i <file1> -i <file2> -i <file3>

通过附加到 Bash 数组,这相对容易处理,如下所示:

infiles=()
while getopts ":i:o:" opt; do
  case $opt in
  i)
    infiles+=("${OPTARG}")
  ;;
  esac
done

稍后您可以迭代这些值:

for inputfile in "${infiles[@]}"; do
  ...
done

阅读bash arrays了解更多信息。

如果您不喜欢该解决方案,您可以以类似于some of the answers 的方式实现您自己的选项解析,以解决我在第一段中链接到的问题。这将允许您获得所需的命令行语义,尽管我认为行为与典型程序的行为方式不一致。

【讨论】:

  • 非常感谢您的回答。我会研究这些选项。
最近更新 更多