2012-07-31 88 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