2013-02-09 27 views
9

research几天后,我仍然无法找出在.sh脚本中解析cmdline参数的最佳方法。据我引用getopts的cmd是因为它要走的路“提取和检查交换机在不干扰位置参数variables.Unexpected开关,或缺少参数开关,识别和reportedas错误。在Bash中解析命令行参数的最佳方法是什么?

阵地params(例2 - $ @,$#等)在涉及空间时显然不能很好地工作,但可以识别常规和长参数(-p和--longparam)。我注意到,在使用嵌套引号传递参数时,这两种方法都会失败(“这是”“”quotes“”。“)的Ex。这三个代码示例中的哪一个最能说明如何处理cmdline参数? getopt函数不被大师推荐,所以我试图避免它!

实施例1:

#!/bin/bash 
for i in "[email protected]" 
do 
case $i in 
    -p=*|--prefix=*) 
    PREFIX=`echo $i | sed 's/[-a-zA-Z0-9]*=//'` 

    ;; 
    -s=*|--searchpath=*) 
    SEARCHPATH=`echo $i | sed 's/[-a-zA-Z0-9]*=//'` 
    ;; 
    -l=*|--lib=*) 
    DIR=`echo $i | sed 's/[-a-zA-Z0-9]*=//'` 
    ;; 
    --default) 
    DEFAULT=YES 
    ;; 
    *) 
      # unknown option 
    ;; 
esac 
done 
exit 0 

实施例2:

#!/bin/bash 
echo ‘number of arguments’ 
echo "\$#: $#" 
echo ” 

echo ‘using $num’ 
echo "\$0: $0" 
if [ $# -ge 1 ];then echo "\$1: $1"; fi 
if [ $# -ge 2 ];then echo "\$2: $2"; fi 
if [ $# -ge 3 ];then echo "\$3: $3"; fi 
if [ $# -ge 4 ];then echo "\$4: $4"; fi 
if [ $# -ge 5 ];then echo "\$5: $5"; fi 
echo ” 

echo ‘using [email protected]’ 
let i=1 
for x in [email protected]; do 
echo "$i: $x" 
let i=$i+1 
done 
echo ” 

echo ‘using $*’ 
let i=1 
for x in $*; do 
echo "$i: $x" 
let i=$i+1 
done 
echo ” 

let i=1 
echo ‘using shift’ 
while [ $# -gt 0 ] 
do 
echo "$i: $1" 
let i=$i+1 
shift 
done 

[/bash] 

output: 

bash> commandLineArguments.bash 
number of arguments 
$#: 0 

using $num 
$0: ./commandLineArguments.bash 

using [email protected] 

using $* 

using shift 
#bash> commandLineArguments.bash "abc def" g h i j* 

实施例3:

#!/bin/bash 

while getopts ":a:" opt; do 
    case $opt in 
    a) 
     echo "-a was triggered, Parameter: $OPTARG" >&2 
     ;; 
    \?) 
     echo "Invalid option: -$OPTARG" >&2 
     exit 1 
     ;; 
    :) 
     echo "Option -$OPTARG requires an argument." >&2 
     exit 1 
     ;; 
    esac 
done 

exit 0 
+1

可能的重复[如何在bash中解析命令行参数?](http://stackoverflow.com/questions/192249/how-do-i-parse-command-line-arguments-in-bash) – 2013-11-12 12:45:47

回答

18

我发现使用getopt是最简单的。它提供了正确的处理参数,否则就很棘手。例如,getopt将知道如何处理在命令行上指定的长选项的参数,如--arg=option--arg option

在解析传递给shell脚本的任何输入时,有用的是使用"[email protected]"变量。请参阅bash手册页,了解它与[email protected]的不同之处。它确保您可以处理包含空格的参数。

这里是我可能写的剧本来分析一些简单的命令行参数的例子:

#!/bin/bash 

args=$(getopt -l "searchpath:" -o "s:h" -- "[email protected]") 

eval set -- "$args" 

while [ $# -ge 1 ]; do 
     case "$1" in 
       --) 
        # No more options left. 
        shift 
        break 
        ;; 
       -s|--searchpath) 
         searchpath="$2" 
         shift 
         ;; 
       -h) 
         echo "Display some help" 
         exit 0 
         ;; 
     esac 

     shift 
done 

echo "searchpath: $searchpath" 
echo "remaining args: $*" 

而像这样用于显示的空间和报价都被保留:

[email protected]:~/bin$ ./getopt_test --searchpath "File with spaces and \"quotes\"." 
searchpath: File with spaces and "quotes". 
remaining args: other args 

一些关于使用getopt的基本信息可以发现here

+2

这是getopt Austin的一个很好的例子。这个特殊的主题已经在[stackoverflow]上进行了广泛的讨论(http://stackoverflow.com/questions/402377/using-getopts-in-bash-shell-script-to-get-long-and-short-command-line-选项/ 7680682#7680682)。不同之处在于普通的getopt不如getopts强壮,并且不适用于旧系统。只要有相同开关的短版本,Getopts就可以解析长开关,因此需要稍微调整一下。我会坚持w/getopts。我更愿意使用内置函数而不是旧版exec(getopt)来实现专业脚本。 – LogicalConfusion 2013-02-10 09:51:38

0

如果你想避免使用getopt你可以n使用这个很好的快速方法:
- 将所有选项的帮助定义为##注释(如您所愿自定义);
- 为每个选项定义一个具有相同名称的函数;
- 将此脚本的最后五行复制到脚本中(魔术)。

例如:日志。SH

#!/bin/sh 
## $PROG 1.0 - Print logs [2017-10-01] 
## Compatible with bash and dash/POSIX 
## 
## Usage: $PROG [OPTION...] [COMMAND]... 
## Options: 
## -i, --log-info   Set log level to info (default) 
## -q, --log-quiet  Set log level to quiet 
## -l, --log MESSAGE  Log a message 
## Commands: 
## -h, --help    Displays this help and exists 
## -v, --version   Displays output version and exists 
## Examples: 
## $PROG -i myscrip-simple.sh > myscript-full.sh 
## $PROG -r myscrip-full.sh > myscript-simple.sh 
PROG=${0##*/} 
LOG=info 
die() { echo [email protected] >&2; exit 2; } 

log_info() { 
    LOG=info 
} 
log_quiet() { 
    LOG=quiet 
} 
log() { 
    [ $LOG = info ] && echo "$1"; return 1 ## number of args used 
} 
help() { 
    grep "^##" "$0" | sed -e "s/^...//" -e "s/\$PROG/$PROG/g"; exit 0 
} 
version() { 
    help | head -1 
} 

[ $# = 0 ] && help 
while [ $# -gt 0 ]; do 
    CMD=$(grep -m 1 -Po "^## *$1, --\K[^= ]*|^##.* --\K${1#--}(?:[= ])" go.sh | sed -e "s/-/_/g") 
    if [ -z "$CMD" ]; then echo "ERROR: Command '$1' not supported"; exit 1; fi 
    shift; eval "$CMD" [email protected] || shift $? 2> /dev/null 
done 

测试:

./log.sh --log yep --log-quiet -l nop -i -l yes会产生:

yep 
yes 

顺便说一句:这是一个与POSIX兼容!

相关问题