getopts可以解析bash脚本的子集';让我们来谈谈你的论点,剩下的就完好无损了?
我正在使用getopts可以解析bash脚本的子集';让我们来谈谈你的论点,剩下的就完好无损了?,bash,getopts,Bash,Getopts,我正在使用getopts解析bash脚本中的参数。我想做两件事: 从“$@” 将未处理的选项保留在“$@” 以命令行为例 $ foo -a val_a -b val_b -c -d -e -f val_f positional_l positional_2 ... 其中foo使用getopts解析由'b:c'的optstring定义的选项,之后需要将“$@”保留为 `-a val_a -d -e -f val_f positional_l positional_2 ...` 我需要做两件
getopts
解析bash
脚本中的参数。我想做两件事:
- 从
“$@”
- 将未处理的选项保留在
“$@”
$ foo -a val_a -b val_b -c -d -e -f val_f positional_l positional_2 ...
其中foo
使用getopts
解析由'b:c'
的optstring定义的选项,之后需要将“$@”
保留为
`-a val_a -d -e -f val_f positional_l positional_2 ...`
我需要做两件事:
- 解析可能给出的选项子集
- 保留所有其他选项不变
foo
必须使用它识别的选项来确定另一个脚本bar
,它必须将剩余的“@”
传递到该脚本
通常,当遇到无法识别的选项时,getopts
会停止,但我需要它继续(直到任何--
)。我需要它来处理和删除它认可的选项,而忽略那些它不认可的选项
我确实尝试在
foo
选项和bar
选项之间使用-
来解决我的问题,但是如果-
后面的文本以-
开头,则getopts
似乎会失败(我尝试了,但无法摆脱连字符)
无论如何,我不想使用--
,因为我希望条的存在对foo
的调用方有效透明,并且我希望foo
的调用方能够以任何顺序呈现选项
我还尝试在foo
中列出所有bar
选项(即对optstring使用'a:b:cdef:'
),但没有处理它们,但我需要在发生时从“$@”
中删除处理过的选项。我不知道怎么做(shift
不允许指定位置)
我可以手动重建一个新的选项列表(见我自己的答案),但我想知道是否有更好的方法 您可以手动重建选项列表,如本例所示,该列表处理-b
和-c
选项,并传递任何保持不变的内容
#!/bin/bash
while getopts ":a:b:cdef:" opt
do
case "${opt}" in
b) file="$OPTARG" ;;
c) ;;
*) opts+=("-${opt}"); [[ -n "$OPTARG" ]] && opts+=("$OPTARG") ;;
esac
done
shift "$((OPTIND-1))"
./$file "${opts[@]}" "$@"
所以
将调用bar
,作为选项b
的参数,如下所示
./bar -a 'foo bar' -d -e -f baz one two 'three and four' five
此解决方案的缺点是,optstring必须包含直通选项(即:a:b:cdef:“
”,而不是首选的”:b:c“
)
用重构的参数列表替换参数列表可以这样做:
set -- "${opts[@]}" "$@"
这将使
“$@”
包含问题中指定的未处理参数。尝试以下操作,只需要事先知道脚本自己的选项即可:
#!/usr/bin/env bash
passThru=() # init. pass-through array
while getopts ':cb:' opt; do # look only for *own* options
case "$opt" in
b)
file="$OPTARG";;
c) ;;
*) # pass-thru option, possibly followed by an argument
passThru+=( "-$OPTARG" ) # add to pass-through array
# see if the next arg is an option, and, if not,
# add it to the pass-through array and skip it
if [[ ${@: OPTIND:1} != -* ]]; then
passThru+=( "${@: OPTIND:1}" )
(( ++OPTIND ))
fi
;;
esac
done
shift $((OPTIND - 1))
passThru+=( "$@" ) # append remaining args. (operands), if any
./"$file" "${passThru[@]}"
注意事项:有两种类型的歧义无法通过这种方式解决:
#!/usr/bin/env bash
passThru=() # init. pass-through array
while getopts ':cb:' opt; do # look only for *own* options
case "$opt" in
b)
file="$OPTARG";;
c) ;;
*) # pass-thru option, possibly followed by an argument
passThru+=( "-$OPTARG" ) # add to pass-through array
# see if the next arg is an option, and, if not,
# add it to the pass-through array and skip it
if [[ ${@: OPTIND:1} != -* ]]; then
passThru+=( "${@: OPTIND:1}" )
(( ++OPTIND ))
fi
;;
esac
done
shift $((OPTIND - 1))
passThru+=( "$@" ) # append remaining args. (operands), if any
./"$file" "${passThru[@]}"
- 对于带有选项参数的传递选项,此方法仅在参数未直接附加到选项时有效。
例如,
有效,但-aval\u a
无效(在-aval\u a
参数中没有getopts
,这将被解释为一个选项组,并将其转换为多个选项a:
,-a
,-v
,-a
,-l
)-a
- 正如在一篇关于这个问题的评论中指出的,
可以是带有选项参数-a-b
的选项-b
(这恰好看起来像一个选项本身),也可以是不同的选项-a
和-a
;上述方法将实现后者-b
要解决这些含糊不清的问题,您必须坚持,这有一个缺点,就是需要事先了解所有可能的传递选项。一个(似乎无法克服)问题:如果您看到
-a-b3
,是一个未知选项-a
,没有参数,后面跟着预期的-b
选项,或者它是一个未知的选项-a
,带有一个参数-b
,后跟一个位置参数3
?@chepner:这一点很好。另一个问题是:-ab
选项-a
带有选项参数b
,或者一个选项组被解释为-a
和-b
?这看起来更难以克服:),除了通配符的情况外,与我所拥有的类似。我认为这些警告是相当模糊的,可以合理忽略,以获得不需要事先了解传递参数的好处。我不知道你能改变getopts变量。很好的解决方案。