2013-03-20 204 views
9

我试图创建一个脚本这将有可选选项的标志。使用getopts可以在标志后面指定一个强制参数(使用冒号),但我想保留它为可选。如何创建带有可选参数的bash脚本的一个标志

这将是这样的:

./install.sh -a 3 

./install.sh -a3 

其中 'a' 是标志和 '3' 是个遵循可选参数。

在此先感谢。

回答

8

getopt exter nal程序允许选项通过向选项名称添加双冒号来获得单个可选参数。

# Based on a longer example in getopt-parse.bash, included with 
# getopt 
TEMP=$(getopt -o a:: -- "[email protected]") 
eval set -- "$TEMP" 
while true ; do 
    case "$1" in 
    -a) 
     case "$2" in 
      "") echo "Option a, no argument"; shift 2 ;; 
      *) echo "Option a, argument $2"; shift 2;; 
     esac ;; 
    --) shift; break ;; 
    *) echo "Internal error!"; exit 1 ;; 
    esac 
done 
+1

执行:'./install.sh -a 3'给出了“选项a,没有argment”但参数是“3” – Alepac 2013-03-20 14:00:39

+1

'getopt'似乎没有以允许选项和其可选参数之间的空格。 – chepner 2013-03-20 14:44:07

+1

从'man getopt':“如果选项有可选参数,则必须在选项字符后面直接写入(如果存在)。” – l0b0 2013-03-20 16:46:20

-1

使用getopt的功能。在大多数系统中,man getopt将产生文档它,甚至在脚本中使用它的例子。从我系统上的手册页:

以下代码片段显示了如何处理参数 以获取可以采用选项-a和-b以及需要参数的选项-o, 的命令。

 args=`getopt abo: $*` 
     # you should not use `getopt abo: "[email protected]"` since that would parse 
     # the arguments differently from what the set command below does. 
     if [ $? != 0 ] 
     then 
       echo 'Usage: ...' 
       exit 2 
     fi 
     set -- $args 
     # You cannot use the set command with a backquoted getopt directly, 
     # since the exit code from getopt would be shadowed by those of set, 
     # which is zero by definition. 
     for i 
     do 
       case "$i" 
       in 
         -a|-b) 
           echo flag $i set; sflags="${i#-}$sflags"; 
           shift;; 
         -o) 
           echo oarg is "'"$2"'"; oarg="$2"; shift; 
           shift;; 
         --) 
           shift; break;; 
       esac 
     done 
     echo single-char flags: "'"$sflags"'" 
     echo oarg is "'"$oarg"'" 

此代码将接受任何以下作为等效的:

 cmd -aoarg file file 
     cmd -a -o arg file file 
     cmd -oarg -a file file 
     cmd -a -oarg -- file file 
+0

'getopt'是正确的答案,但你的长期示例不演示如何实现其参数也是可选的选项。 – chepner 2013-03-20 13:35:45

+0

如果您的参数包含空格,则会中断。 [示例解决方案。](https://github.com/l0b0/unrarr/blob/master/unrarr.sh#L63-L65) – l0b0 2013-03-20 16:45:18

+1

因为标准手册页的内容不符合您的喜好,因此投票反对。好时光。 – 2013-03-20 18:05:37

-1

在bash有一些隐变量:

$#: contains number of arguments for a called script/function 

    $0: contains names of script/function 
    $1: contains first argument 
    $2: contains second argument 
    ... 
    $n: contains n-th argument 

例如:

#!/bin/ksh 

    if [ $# -ne 2 ] 
    then 
     echo "Wrong number of argument - expected 2 : $#" 
    else 
     echo "Argument list:" 
     echo "\t$0" 
     echo "\t$1" 
     echo "\t$2" 
    fi 
+0

的问题是问如何定义其参数也是可选的选项。 – chepner 2013-03-20 13:36:50

+0

是的,我更愿意向他解释如何去争辩,而不是给他一个完整的答案。有时候它更适合某人自己找到路...顺便说一句,你的答案应该得到-1,因为你的“虽然是真的”...... – 2013-03-20 13:38:44

+0

@binogure'while true'本身没有错 - 需要是一个终止条件,但这可以是一个'休息'。 – 2013-03-20 13:57:02

-1

我的解决办法:

#!/bin/bash 
count=0 
skip=0 
flag="no flag" 
list=([email protected]) #put args in array 
for arg in [email protected] ; do #iterate over array 
    count=$(($count+1)) #update counter 
    if [ $skip -eq 1 ]; then #check if we have to skip this args 
     skip=0 
     continue 
    fi 
    opt=${arg:0:2} #get only first 2 chars as option 
    if [ $opt == "-a" ]; then #check if option equals "-a" 
     if [ $opt == $arg ] ; then #check if this is only the option or has a flag 
      if [ ${list[$count]:0:1} != "-" ]; then #check if next arg is an option 
       skip=1 #skip next arg 
       flag=${list[$count]} #use next arg as flag 
      fi 
     else 
      flag=${arg:2} #use chars after "-a" as flag 
     fi 
    fi 
done 

echo $flag 
+0

'in $ @'是多余的。另外,POSIX'sh'没有数组。 '=='不可移植。 – l0b0 2013-03-20 16:47:59

+0

@ l0b0为什么'$ @'中多余?它可以用'$ list'代替,但是需要。我同意代码不可移植,并且我将标题更改为'#!/ bin/bash' – Alepac 2013-03-22 09:02:50

+0

因为'arg'默认会遍历'“$ @”'。 – l0b0 2013-03-22 12:30:44

1

以下是没有getopt,它需要一个可选的参数与-a标志:

for WORD; do 
     case $WORD in 
      -a?) echo "single arg Option" 
       SEP=${WORD:2:1} 
       echo $SEP 
       shift ;; 
      -a) echo "split arg Option" 
       if [[ ${2:0:1} != "-" && ${2:0:1} != ""]] ; then 
       SEP=$2 
       shift 2 
       echo "arg present" 
       echo $SEP 
       else 
       echo "optional arg omitted" 
       fi ;; 
      -a*) echo "arg Option" 
       SEP=${WORD:2} 
       echo $SEP 
       shift ;; 
      -*) echo "Unrecognized Short Option" 
       echo "Unrecognized argument" 
      ;; 
     esac 
done 

其他选项/标志也可以很容易地添加。

+0

的确,外壳不是必需的。编辑它。谢谢@ l0b0 – Dipto 2013-03-21 05:47:26

+1

Nit:'in“$ @”'不是必需的。 '为WORD;做'会循环论证。 – l0b0 2013-03-21 09:01:04

相关问题