如何在参数以 - 开头时移动参数 -

Ale*_*lls 3 bash shell-script

假设我有一个 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
Run Code Online (Sandbox Code Playgroud)

这似乎有效,但我想知道这是否是一个很好的通用解决方案,可以始终让 'omg' 成为第一个“合法”参数。是否有任何可能失败的边缘情况?

换句话说,-a、-f、-c 都是 gmx 的参数。而omg接下来的一切都将在子进程中运行。

sch*_*ily 8

官方和最好的方法是 t 使用getopts内置来解析命令行选项。

有关更多信息,请参阅手册页。

注意可能很重要:bash不支持长选项。

如果你喜欢用脚本处理长选项,你有两个支持它们的 shell:ksh93和bosh. 两种 shell 都支持长选项,就像getopt(3)Solaris 上的 libc 中的函数所支持的那样。请参阅 bosh 手册页(当前从第 43 页开始:

http://schlytools.sourceforge.net/man/man1/bosh.1.html

getopts "f:(file)(input-file)o:(output-file)" OPT
Run Code Online (Sandbox Code Playgroud)

支持例如-f带有参数的选项,并且该选项有一个长选项别名--file和此选项的第二个别名--input-file

ksh93 也支持这一点,即使它没有记录在 ksh93 手册页中。


Kus*_*nda 5

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' "$@"
Run Code Online (Sandbox Code Playgroud)

这用于getopts解析命令行选项。while一旦找到第一个非选项,循环就会终止,并且shift将把处理过的选项移出$@只留下非选项操作数$@。

剧本

#!/bin/sh

gmx () {
    while getopts ':' opt; do
        :
    done

    shift "$(( OPTIND - 1 ))"
    printf 'arg: %s\n' "$@"
}

gmx -a --foo -c omg lol
Run Code Online (Sandbox Code Playgroud)

会输出

arg: omg
arg: lol
Run Code Online (Sandbox Code Playgroud)

由于您对实际选项不感兴趣,因此您显然可以执行一个简单的循环,例如

for opt do
    case $opt in
        -*) shift ;;
        *)  break
     esac
done

printf 'arg: %s\n' "$@"
Run Code Online (Sandbox Code Playgroud)

这会遍历所有参数,将每个以破折号开头的参数移开,并以第一个不以破折号开头的参数结束。