getopts 参数可以与其他输入结合使用吗?

Isa*_*hen 3 bash shell-script getopts

我正在编写一个脚本,该脚本将字符串作为输入以及用户可以通过使用参数作为指示符来选择的其他选项。换句话说,是这样的:

./script "My input string" -pxz
Run Code Online (Sandbox Code Playgroud)

或者

./script -pxz "My input string"
Run Code Online (Sandbox Code Playgroud)

但我遇到了以下问题。输入非 getopts 样式的参数后, getopts 命令似乎停止工作。检查一下,例如:

#!/bin/bash

while getopts "ab" arg; do
    echo $arg received
done
Run Code Online (Sandbox Code Playgroud)

当我们运行它时,我们得到:

$ ./example.sh -a -b -a string -b
a received
b received
a received
$
Run Code Online (Sandbox Code Playgroud)

它停在“string”处并且不会继续。getopts 命令返回非零退出状态,因为“string”不是它期望读取的参数类型,并且 while 循环结束。我尝试添加第二个,while getopts但这没有任何作用。getopts 的“读头”仍然停留在该“字符串”参数上,并且将再次以非零退出状态退出。

这意味着,看起来,我无法让用户先输入字符串,然后输入选项,因为 getopts 永远无法读取字符串并到达那里。所以我不能这样做:

./script "My input string" -pxz
Run Code Online (Sandbox Code Playgroud)

另一方面,如果我告诉用户首先输入他们的选项,然后输入字符串,我就会遇到如何检索字符串的问题。通常,如果没有选择,我会这样做:

string="$1"
Run Code Online (Sandbox Code Playgroud)

但现在由于有选项,而且我不知道有多少个,我不再知道字符串占据什么位置。那么我怎样才能找回它呢?

现在,理想情况下,我的脚本实际上应该能够以这两种方式甚至两者的组合来工作。它应该能够处理如下输入:

./script -p "My input string" -xz
Run Code Online (Sandbox Code Playgroud)

那么我该如何解决这个问题呢?

ilk*_*chu 5

如果您使用的是 Linux,并且您有getopt来自 util-linux(或 Busybox)的命令,它也可以像 GNU 工具那样对参数进行重新排序。它还支持参数、选项参数、可选选项参数中的空格以及--终止选项处理。

标准行为是在看到第一个非选项时停止选项处理,因此其他实现可能不支持混合选项和非选项。POSIXLY_CORRECT如果设置的话,即使是 GNU 也不支持它。

无论如何,使用下面的脚本:

$ ./opts.sh -a 123 "arg with space" more -bc args -- -also -args
option -a with arg '123'
option -b
option -c
remaining arguments (5):
<arg with space> <more> <args> <-also> <-args> 
Run Code Online (Sandbox Code Playgroud)

opts.sh:

#!/bin/bash

getopt -T
if [ "$?" -ne 4 ]; then
    echo "wrong version of 'getopt' installed, exiting..." >&2
    exit 1
fi 
params="$(getopt -o a:bc -- "$@")"
eval set -- "$params"
while [ "$#" -gt 0 ]; do
    case "$1" in
    -a)
        echo "option -a with arg '$2'"
        shift 2;;
    -b)
        echo "option -b"
        shift;;
    -c)
        echo "option -c"
        shift;;
    --) 
        shift
        break;;
     *) 
        echo "something else: '$1'"
        shift;;
    esac
done
echo "remaining arguments ($#):"
printf "<%s> " "$@"
echo
Run Code Online (Sandbox Code Playgroud)

(请注意,上述脚本仅getopt适用于与 util-linux 增强功能兼容的实现。其他“传统”实现存在参数中的空格等问题。该getopt -T测试用于检测实现是否兼容。)