2013-02-09 61 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兼容!

相關問題