2011-08-15 22 views
176

我知道,我可以輕鬆地獲得定位參數,這樣在bash:如何獲得的參數與國旗在bash腳本

$0$1

我希望能夠使用標誌選項像這樣指定什麼每個參數用於:

mysql -u user -h host 

什麼是讓-u param值和標誌,而不是由位置-h param價值的最佳方式是什麼?

+2

它可能在http://unix.stackexchange.com/上查詢/檢查是個好主意,以及 – MRR0GERS

+6

谷歌的「bash getopts」 - 很多教程。 –

+48

@ glenn-jackman:我現在肯定會google了一下,我知道這個名字。關於谷歌的事情是 - 提出一個問題 - 你應該已經知道50%的答案。 – Stann

回答

202

這是成語我通常使用:

while test $# -gt 0; do 
     case "$1" in 
       -h|--help) 
         echo "$package - attempt to capture frames" 
         echo " " 
         echo "$package [options] application [arguments]" 
         echo " " 
         echo "options:" 
         echo "-h, --help    show brief help" 
         echo "-a, --action=ACTION  specify an action to use" 
         echo "-o, --output-dir=DIR  specify a directory to store output in" 
         exit 0 
         ;; 
       -a) 
         shift 
         if test $# -gt 0; then 
           export PROCESS=$1 
         else 
           echo "no process specified" 
           exit 1 
         fi 
         shift 
         ;; 
       --action*) 
         export PROCESS=`echo $1 | sed -e 's/^[^=]*=//g'` 
         shift 
         ;; 
       -o) 
         shift 
         if test $# -gt 0; then 
           export OUTPUT=$1 
         else 
           echo "no output dir specified" 
           exit 1 
         fi 
         shift 
         ;; 
       --output-dir*) 
         export OUTPUT=`echo $1 | sed -e 's/^[^=]*=//g'` 
         shift 
         ;; 
       *) 
         break 
         ;; 
     esac 
done 

關鍵點是:

  • $#是參數
  • 數量,同時循環查找所有的提供的參數,匹配上他們的價值觀在案件陳述
  • 轉移採取第一個。您可以在case語句內多次移動以獲取多個值。
+2

'--action *'和'--output-dir *'個案有什麼作用? – Lucio

+1

他們只是保存他們進入環境的價值。 – Flexo

+3

我猜@Lucio是什麼意思...... * – arod

35

getopt的是你的朋友..一個簡單的例子:

function f() { 
TEMP=`getopt --long -o "u:h:" "[email protected]"` 
eval set -- "$TEMP" 
while true ; do 
    case "$1" in 
     -u) 
      user=$2 
      shift 2 
     ;; 
     -h) 
      host=$2 
      shift 2 
     ;; 
     *) 
      break 
     ;; 
    esac 
done; 

echo "user = $user, host = $host" 
} 

f -u myself -h some_host 

應該有你的/ usr/bin目錄的各種例子。

+1

在Ubuntu機器上至少可以在目錄'/ usr/share/doc/util-linux/examples'中找到一個更廣泛的例子。 –

209

此示例使用bash的內置getopts命令是從Google Shell Style Guide

verbose='false' 
aflag='' 
bflag='' 
files='' 

while getopts 'abf:v' flag; do 
    case "${flag}" in 
    a) aflag='true' ;; 
    b) bflag='true' ;; 
    f) files="${OPTARG}" ;; 
    v) verbose='true' ;; 
    *) error "Unexpected option ${flag}" ;; 
    esac 
done 

注:如果一個字符後面跟一個冒號(如f:),該選項預計將有一個說法。

實例:./script -v -a -b -f filename

使用getopts的具有優於接受的回答幾個優點:

  • while條件是一個很大的可讀性和顯示了所接受的選擇是
  • 清潔器的代碼;不計算參數的數量和不斷變化的
  • 你可以加入的選項(例如-a -b -c-abc

然而,一個很大的缺點是,它不支持長選項中,只有單字符選項。

+16

有人想知道爲什麼使用bash內建這個答案不是最大的答案 –

+5

這應該是被接受的答案 – woens

+2

後人:在'abf:v'後面的冒號表示-f需要一個額外的參數(文件名在這個案件)。 – zahbaz

4

另一種方法是使用類似下面的例子中,這將允許您使用長--image或短-i標籤,也允許編譯-i =「example.jpg」或獨立-i example.jpg傳入參數的方法。

# declaring a couple of associative arrays 
declare -A arguments=(); 
declare -A variables=(); 

# declaring an index integer 
declare -i index=1; 

# any variables you want to use here 
# on the left left side is argument label or key (entered at the command line along with it's value) 
# on the right side is the variable name the value of these arguments should be mapped to. 
# (the examples above show how these are being passed into this script) 
variables["-gu"]="git_user"; 
variables["--git-user"]="git_user"; 
variables["-gb"]="git_branch"; 
variables["--git-branch"]="git_branch"; 
variables["-dbr"]="db_fqdn"; 
variables["--db-redirect"]="db_fqdn"; 
variables["-e"]="environment"; 
variables["--environment"]="environment"; 

# [email protected] here represents all arguments passed in 
for i in "[email protected]" 
do 
    arguments[$index]=$i; 
    prev_index="$(expr $index - 1)"; 

    # this if block does something akin to "where $i contains =" 
    # "%=*" here strips out everything from the = to the end of the argument leaving only the label 
    if [[ $i == *"="* ]] 
    then argument_label=${i%=*} 
    else argument_label=${arguments[$prev_index]} 
    fi 

    # this if block only evaluates to true if the argument label exists in the variables array 
    if [[ -n ${variables[$argument_label]} ]] 
    then 
     # dynamically creating variables names using declare 
     # "#$argument_label=" here strips out the label leaving only the value 
     if [[ $i == *"="* ]] 
      then declare ${variables[$argument_label]}=${i#$argument_label=} 
      else declare ${variables[$argument_label]}=${arguments[$index]} 
     fi 
    fi 

    index=index+1; 
done; 

# then you could simply use the variables like so: 
echo "$git_user"; 
3

我認爲服務器可以作爲您想要實現的簡單示例。沒有必要使用外部工具。 Bash建立了它,工具可以爲你完成這項工作。

function DOSOMETHING { 

    while test $# -gt 0; do 
      case "$1" in 
       -first) 
        shift 
        first_argument=$1 
        shift 
        ;; 
       -last) 
        shift 
        last_argument=$1 
        shift 
        ;; 
       *) 
        echo "$1 is not a recognized flag!" 
        return 1; 
        ;; 
      esac 
    done 

    echo "First argument : $first_argument"; 
    echo "Last argument : $last_argument"; 
} 

這將允許您使用國旗所以無論哪個命令你正在傳遞的參數,你會得到正確的行爲。

例子:

DOSOMETHING -last "Adios" -first "Hola" 

輸出:

First argument : Hola 
Last argument : Adios 

可以將此功能添加到您的個人資料或把它放在一個腳本里面。

謝謝!

編輯: 保存此爲AA文件,然後執行它yourfile.sh -last "Adios" -first "Hola"

#!/bin/bash 
while test $# -gt 0; do 
      case "$1" in 
       -first) 
        shift 
        first_argument=$1 
        shift 
        ;; 
       -last) 
        shift 
        last_argument=$1 
        shift 
        ;; 
       *) 
        echo "$1 is not a recognized flag!" 
        return 1; 
        ;; 
      esac 
    done 

    echo "First argument : $first_argument"; 
    echo "Last argument : $last_argument"; 
+0

我使用上面的代碼&當運行它不打印任何東西。 './hello.sh DOSOMETHING -last「Adios」-first「Hola」' – dinu0101

+0

@ dinu0101這是一項功能。不是腳本。你應該使用它作爲DOSOMETHING -last「Adios」-first「Hola」 –

+0

Thanks @Matias。瞭解。如何在腳本內部運行。 – dinu0101

0

我喜歡羅伯特·麥克馬漢的回答這裏最好的,因爲它似乎最容易使之成爲共享包括文件中的任何腳本來使用。但它似乎有一個瑕疵與行if [[ -n ${variables[$argument_label]} ]]投擲消息,「變量:壞數組下標」。我沒有代表評論,我懷疑這是正確的'修復',但包裝在if [[ -n $argument_label ]] ; then清理它。

下面是我最終得到的代碼,如果你知道更好的方法,請給Robert的答案添加評論。

包含文件 「flags-declares.sh」

# declaring a couple of associative arrays 
declare -A arguments=(); 
declare -A variables=(); 

# declaring an index integer 
declare -i index=1; 

包含文件 「flags-arguments.sh」

# [email protected] here represents all arguments passed in 
for i in "[email protected]" 
do 
    arguments[$index]=$i; 
    prev_index="$(expr $index - 1)"; 

    # this if block does something akin to "where $i contains =" 
    # "%=*" here strips out everything from the = to the end of the argument leaving only the label 
    if [[ $i == *"="* ]] 
    then argument_label=${i%=*} 
    else argument_label=${arguments[$prev_index]} 
    fi 

    if [[ -n $argument_label ]] ; then 
    # this if block only evaluates to true if the argument label exists in the variables array 
    if [[ -n ${variables[$argument_label]} ]] ; then 
     # dynamically creating variables names using declare 
     # "#$argument_label=" here strips out the label leaving only the value 
     if [[ $i == *"="* ]] 
     then declare ${variables[$argument_label]}=${i#$argument_label=} 
     else declare ${variables[$argument_label]}=${arguments[$index]} 
     fi 
    fi 
    fi 

    index=index+1; 
done; 

你 「script.sh」

. bin/includes/flags-declares.sh 

# any variables you want to use here 
# on the left left side is argument label or key (entered at the command line along with it's value) 
# on the right side is the variable name the value of these arguments should be mapped to. 
# (the examples above show how these are being passed into this script) 
variables["-gu"]="git_user"; 
variables["--git-user"]="git_user"; 
variables["-gb"]="git_branch"; 
variables["--git-branch"]="git_branch"; 
variables["-dbr"]="db_fqdn"; 
variables["--db-redirect"]="db_fqdn"; 
variables["-e"]="environment"; 
variables["--environment"]="environment"; 

. bin/includes/flags-arguments.sh 

# then you could simply use the variables like so: 
echo "$git_user"; 
echo "$git_branch"; 
echo "$db_fqdn"; 
echo "$environment";