假设我有一个 bash 函数,它应该删除所有以“-”开头的参数,直到它到达不以“-”开头的参数。
gmx(){
local options=( );
while [ "${1:0:1}" == "-" ]; do
options+=("${1}")
shift 1;
done
echo "first legit arg: $1"
"$@" # omg will be executed here, like `omg --rolo`
}
gmx -a -f -c omg --rolo
这似乎有效,但我想知道这是否是一个很好的通用解决方案,可以始终让“omg”成为第一个“合法”参数。是否存在可能失败的边缘情况?
换句话说,-a、-f、-c 都是 gmx 的参数。而omg
接下来的一切都将在子进程中运行。
答案1
官方和最好的方法是不要使用getopts
内置函数来解析命令行选项。
请参阅手册页以获取更多信息。
注释可能很重要:bash
不支持长选项。
如果您喜欢脚本来处理长选项,您有两个支持它们的 shell:ksh93
和bosh
。两个 shell 都支持长选项,就像getopt(3)
Solaris 上 libc 中的函数支持它们一样。请参阅 bosh 手册页(当前从第 43 页开始:
http://schilytools.sourceforge.net/man/man1/bosh.1.html
getopts "f:(file)(input-file)o:(output-file)" OPT
-f
支持例如带有参数的选项,并且该选项具有长选项别名--file
和该选项的第二个别名--input-file
ksh93 也支持这一点,尽管 ksh93 手册页中没有对此进行记录。
答案2
while getopts ':' opt; do
: # This is where ordinarily a case statement would be,
# case $opt in ... esac
# But we use : as a no-op
done
shift "$(( OPTIND - 1 ))"
printf 'arg: %s\n' "$@"
这用于getopts
解析命令行选项。while
一旦找到第一个非选项,循环就会终止,并且会将shift
已处理的选项移走,$@
只留下非选项操作数$@
。
剧本
#!/bin/sh
gmx () {
while getopts ':' opt; do
:
done
shift "$(( OPTIND - 1 ))"
printf 'arg: %s\n' "$@"
}
gmx -a --foo -c omg lol
会输出
arg: omg
arg: lol
由于您对真正的选项不感兴趣,因此您显然可以执行一个简单的循环,例如
for opt do
case $opt in
-*) shift ;;
*) break
esac
done
printf 'arg: %s\n' "$@"
这会循环遍历所有参数,将每个以破折号开头的参数移开,并以第一个不以破折号开头的参数结束。
答案3
如果你能控制方式,一个更简单的解决方案GMX被调用,只是使用 来将包装器的参数与包装的命令分开--
,这样
gmx garg garg garg -- warg warg warg
在哪里
- 加尔格表示使用的参数GMX。
- 座狼表示发送到的参数包装纸。
如果您想要方便地省略--
,您可以将其设为可选,并在尝试“智能”检查之前搜索它。