Shell脚本:混合getopts与位置参数可能吗?

我想devise一个shell脚本作为几个脚本的包装。 我想使用getoptsmyshell.sh指定参数, myshell.sh其余参数以相同的顺序传递给指定的脚本。

如果执行myshell.sh ,如下所示:

 myshell.sh -h hostname -s test.sh -d waittime param1 param2 param3 myshell.sh param1 param2 -h hostname param3 -d waittime -s test.sh myshell.sh param1 -h hostname -d waittime -s test.sh param2 param3 

以上所有应该可以称为

 test.sh param1 param2 param3 

是否可以利用 myshell.sh 的选项参数 并将其余参数发布到底层脚本中?

对不起,对一个旧线程发表评论,但认为我会为那些正在寻找如何做到这一点的人发布信息…

我想做一些类似于OP的事情,我在这里和这里find了我需要的相关信息

本质上,如果你想做的事情如:

 script.sh [options] ARG1 ARG2 

然后让你的select是这样的:

 while getopts "h:u:p:d:" flag; do case "$flag" in h) HOSTNAME=$OPTARG;; u) USERNAME=$OPTARG;; p) PASSWORD=$OPTARG;; d) DATABASE=$OPTARG;; esac done 

然后你可以得到你的位置参数是这样的:

 ARG1=${@:$OPTIND:1} ARG2=${@:$OPTIND+1:1} 

更多的信息和细节可以通过上面的链接。

希望帮助!

getopts不会分析param1-n选项的组合。

将param1-3与其他选项放在一起是更好的select。

此外,你可以使用已经存在的库,如shflags 。 这是非常聪明的,它很容易使用。

最后一种方法是编写你自己的函数来parsingparams,而不是getopts,只是遍历所有的参数。 这是最难的方法,但它是唯一正确匹配您的期望的方法。

[编辑:修正了两个错别字]

我想到了getopts可以扩展到真正混合选项和位置参数的一种方法。 这个想法是在调用getopts和分配任何发现的位置参数n1n2n3等之间交替:

 parse_args() { _parse_args 1 "$@" } _parse_args() { local n="$1" shift local options_func="$1" shift local OPTIND "$options_func" "$@" shift $(( OPTIND - 1 )) if [ $# -gt 0 ]; then eval test -n \${n$n+x} if [ $? -eq 0 ]; then eval n$n="\$1" fi shift _parse_args $(( n + 1 )) "$options_func" "$@" fi } 

那么在OP的情况下,你可以像这样使用它:

 main() { local n1='' n2='' n3='' local duration hostname script parse_args parse_main_options "$@" echo "n1 = $n1" echo "n2 = $n2" echo "n3 = $n3" echo "duration = $duration" echo "hostname = $hostname" echo "script = $script" } parse_main_options() { while getopts d:h:s: opt; do case "$opt" in d) duration="$OPTARG" ;; h) hostname="$OPTARG" ;; s) script="$OPTARG" ;; esac done } main "$@" 

运行它显示输出:

 $ myshell.sh param1 param2 -h hostname param3 -d waittime -s test.sh n1 = param1 n2 = param2 n3 = param3 duration = waittime hostname = hostname script = test.sh 

只是一个概念的certificate,但也许这对某个人有用。

注意:如果一个使用parse_args函数调用另一个使用parse_args函数, 外部函数声明例如local n4='' ,但是内部的函数不会传递4个或更多的位置参数给内部函数

刚刚把一个quickie变成了一个quickie,它很容易处理一个选项和位置参数的混合(在$ @中只保留位置参数):

 #!/bin/bash while [ ${#} -gt 0 ];do OPTERR=0;OPTIND=1;getopts "p:o:hvu" arg;case "$arg" in p) echo "Path: [$OPTARG]" ;; o) echo "Output: [$OPTARG]" ;; h) echo "Help" ;; v) echo "Version" ;; \?) SET+=("$1") ;; *) echo "Coding error: '-$arg' is not handled by case">&2 ;; esac;shift;[ "" != "$OPTARG" ] && shift;done [ ${#SET[@]} -gt 0 ] && set "" "${SET[@]}" && shift echo -e "=========\nLeftover (positional) parameters (count=$#) are:" for i in `seq $#`;do echo -e "\t$i> [${!i}]";done 

示例输出:

 [root@hots:~]$ ./test.sh 'aa bb' -h -v -u -q 'cc dd' -p 'ee ff' 'gg hh' -o ooo Help Version Coding error: '-u' is not handled by case Path: [ee ff] Output: [ooo] ========= Leftover (positional) parameters (count=4) are: 1> [aa bb] 2> [-q] 3> [cc dd] 4> [gg hh] [root@hots:~]$ 

混合select和参数:

 ARGS="" echo "options :" while [ $# -gt 0 ] do unset OPTIND unset OPTARG while getopts as:c: options do case $options in a) echo "option a no optarg" ;; s) serveur="$OPTARG" echo "option s = $serveur" ;; c) cible="$OPTARG" echo "option c = $cible" ;; esac done shift $((OPTIND-1)) ARGS="${ARGS} $1 " shift done echo "ARGS : $ARGS" exit 1 

结果:

 bash test.sh -a arg1 arg2 -s serveur -c cible arg3 options : option a no optarg option s = serveur option c = cible ARGS : arg1 arg2 arg3 

对于unix选项处理有一些标准,在shell编程中, getopts是强制执行它们的最好方法。 几乎所有现代语言(perl,python)在getopts上都有一个变体。

这只是一个简单的例子:

 command [ options ] [--] [ words ] 
  1. 每个选项必须以短划线开始, -必须由单个字符组成。

  2. GNU项目引入了Long Options,以两个破折号开头,后面跟着一个单词--long_option 。 AST KSH项目有一个getopts,它也支持长选项, 长选项以单个破折号开始-find(1)

  3. 期权可能会或可能不会期望论据。

  4. 任何不以短划线开始的单词,都将结束选项处理。

  5. string--必须被跳过,并将结束选项处理。

  6. 任何剩余的参数保留为位置参数。

Open Group有一个关于Utility Argument Syntax的部分

Eric Raymond的“Unix编程艺术” 有一章介绍了选项字母及其含义的传统unixselect。

你可以试试这个技巧:在使用optargs循环之后,使用这个片段

 #shift away all the options so that only positional agruments #remain in $@ for (( i=0; i<OPTIND-1; i++)); do shift done POSITIONAL="$@" 

但是,这种方法有一个错误:

    在第一个位置参数之后的所有选项都由getopts进行存储,并被视为位置参数 – 事件是正确的(请参阅示例输出:-m和-c在位置参数中)

也许它有更多的错误…

看整个例子:

 while getopts :abc opt; do case $opt in a) echo found: -a ;; b) echo found: -b ;; c) echo found: -c ;; \?) echo found bad option: -$OPTARG ;; esac done #OPTIND-1 now points to the first arguments not beginning with - #shift away all the options so that only positional agruments #remain in $@ for (( i=0; i<OPTIND-1; i++)); do shift done POSITIONAL="$@" echo "positional: $POSITIONAL" 

输出:

 [root@host ~]# ./abc.sh -abc -de -fgh -bca haha blabla -m -c found: -a found: -b found: -c found bad option: -d found bad option: -e found bad option: -f found bad option: -g found bad option: -h found: -b found: -c found: -a positional: haha blabla -m -c