2012-07-31 27 views
35

我想设计一个shell脚本作为几个脚本的包装。我想使用getopts指定myshell.sh的参数,并将其余参数以相同的顺序传递给指定的脚本。Shell脚本:混合getopts与位置参数可能吗?

如果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和后的选项参数底层脚本的剩余参数?

+0

你到底想干什么?你想调用'test.sh param1 param2 param3'到'myshell.sh'中? – 2012-07-31 15:09:39

+0

对不起,如果不清楚的问题。是。我想让我的脚本处理混合的位置参数和getopt值。 getopt中剩下的所有东西都应该和底层的shell脚本一起传递。 – SiB 2012-07-31 15:12:06

+1

只有第一行符合选项处理的unix标准(见下文)。否则做更多的工作是为了得到正确和维护。 – 2012-07-31 22:47:25

回答

65

对不起,评论一个古老的线程,但想到我会发布对于那些像我一样谁正在寻找如何做到这一点...

我想要做类似的东西OP,和我发现我需要herehere

从本质上讲,如果你想要做的事,如相关信息:

script.sh [options] ARG1 ARG2 

然后得到你这样的选择:

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} 

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

希望帮助!

+24

但是这不允许位置参数在OP问题的一部分之前的标志之前。另一种处理位置/之后/标记的标准方法是在你的esac之后执行$((OPTIND-1)),然后正常处理定位。 – Chinasaur 2013-07-23 22:41:33

+1

@Chinasaur当我使用'ARG1 = $ {@:$ OPTIND:1}'后,它同时为'script.sh -h localhost abc'和'script.sh abc -h localhost' =在ARG1中为我工作I在两种情况下都具有“abc”值。你能更具体什么不工作(我误解了)?谢谢! – Betlista 2017-07-14 10:28:11

+0

我无法获得'ARG1'。它是空的。 – Sigur 2017-10-03 02:05:33

3

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

把param1-3放到其他选项中会好得多。

此外,您可以使用已有的库,例如shflags。它非常聪明,易于使用。

最后一种方法是编写自己的函数来解析不带getopts的参数,只需通过case构造迭代所有参数即可。这是最难的方法,但它是唯一正确匹配您的期望的方法。

[编辑:固定在两个错别字]

+0

谢谢。我在这里选择的方式是解析'getopts'参数,然后'shift'并将参数传递给底层脚本。 – SiB 2012-07-31 15:45:01

0

有一些标准的UNIX选项处理,并在shell编程,getopts是执行这些的最佳途径。几乎所有现代语言(perl,python)在getopts上都有一个变体。

这仅仅是一个简单的例子:

command [ options ] [--] [ words ] 
  1. 每个选项都必须以划线,-启动,且必须由单个字符。

  2. GNU项目引入了长选项,从两个破折号--, 开始,后面跟着一个全字--long_option。 AST KSH项目有一个getopts,它也支持长选项,长选项,从一个短划线开始,-,如find(1)

  3. 期权可能会也可能不会期望参数。

  4. 任何不以短划线开头的单词-都会结束选项处理。

  5. 必须跳过字符串--并且将结束选项处理。

  6. 任何剩余的参数都留作位置参数。

公开组对Utility Argument Syntax

雷蒙德的Unix的传统UNIX选择的选项字母及其含义编程has a chapter艺术节。

1

我想到了一种方式,getopts可以扩展到真正混合选项和位置参数。我们的想法是调用getopts然后在OP的情况下给予任何位置发现n1n2

parse_args() { 
    _parse_args 1 "[email protected]" 
} 

_parse_args() { 
    local n="$1" 
    shift 

    local options_func="$1" 
    shift 

    local OPTIND 
    "$options_func" "[email protected]" 
    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" "[email protected]" 
    fi 
} 

参数,n3等之间交替,你可以使用它像:

main() { 
    local n1='' n2='' n3='' 
    local duration hostname script 

    parse_args parse_main_options "[email protected]" 

    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 "[email protected]" 

运行它显示输出:

$ 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 

只是一个概念证明,但也许它是有用的有人。

注:有一个疑难杂症,如果使用parse_args调用使用parse_args另一个功能一个功能外函数声明例如local n4='',但内一个没有 4个或更多的位置参数被传递到内功能

1

仅有捣碎一个匆匆,容易处理的选项和位置参数(只留下位置-PARAMS的混合物在$ @):

#!/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 

输出示例:

[[email protected]:~]$ ./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] 
[[email protected]:~]$ 
+1

这不允许在单个“-abc”参数中组合几个选项。 – 2015-10-27 12:52:42

1

选择采用混合和args:

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 
0

你可以试试这招:while循环与optargs,只要使用这个片段

#shift away all the options so that only positional agruments 
#remain in [email protected] 

for ((i=0; i<OPTIND-1; i++)); do 
    shift 
done 

POSITIONAL="[email protected]" 

但是之后,这种方法有一个缺陷:

    所有第一个位置参数之后的选项由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 [email protected] 

for ((i=0; i<OPTIND-1; i++)); do 
    shift 
done 

POSITIONAL="[email protected]" 

echo "positional: $POSITIONAL" 

输出:

[[email protected] ~]# ./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