2013-05-20 39 views
31

我想在我的.bash_profile中定義的函數內使用getopts。 這個想法是我想傳遞一些標誌到這個函數來改變它的行爲。在Bash函數中使用getopts

下面的代碼:

function t() { 
    echo $* 
    getopts "a:" OPTION 
    echo $OPTION 
    echo $OPTARG 
} 

當我調用它是這樣的:

t -a bc 

我得到這樣的輸出:

-a bc 
? 
  

有什麼不對?我想獲得價值bc而無需手動移動和解析。如何在函數內正確使用getopts

編輯:糾正了我的代碼片段嘗試$ OPTARG,無濟於事

編輯#2:OK原來的代碼是好的,我的殼莫名其妙地被搞砸了。打開一個新窗口解決了它。參考價值確實在$ OPTARG。

回答

64

由於@Ansgar指出,爭論到您的選項將存儲在${OPTARG},但這並不是需要注意使用getopts一個函數內當的嘛。您還需要確保${OPTIND}對於函數是本地的,方法是取消設置或聲明local,否則在多次調用函數時會遇到意外的行爲。

t.sh

#!/bin/bash 

foo() 
{ 
    foo_usage() { echo "foo: [-a <arg>]" 1>&2; exit; } 

    local OPTIND o a 
    while getopts ":a:" o; do 
     case "${o}" in 
      a) 
       a="${OPTARG}" 
       ;; 
      *) 
       foo_usage 
       ;; 
     esac 
    done 
    shift $((OPTIND-1)) 

    echo "a: [${a}], non-option arguments: $*" 
} 

foo 
foo -a bc bar quux 
foo -x 

實例運行:

$ ./t.sh 
a: [], non-option arguments: 
a: [bc], non-option arguments: bar quux 
foo: [-a <arg>] 

如果您註釋掉# local OPTIND,這是你會得到什麼,而不是:

$ ./t.sh 
a: [], non-option arguments: 
a: [bc], non-option arguments: bar quux 
a: [bc], non-option arguments: 

除此之外,它的用法與在函數外部使用時相同。

+7

如果可以的話,我會百回答這個問題的答案。這讓我瘋狂! –

+0

1.)'1&2'中的'1'不是必需的。 2.)你錯過了將'a','o'和'OPTARG'定義爲本地。 3)'exit'不會退出腳本,而只是一個子shell。爲了退出腳本,必須在外殼中設置-e,在子外殼中設置exit 1。這個例子不會觸發問題,但是'MSG = $(foo ...)'會做到這一點。 – ceving

+0

@ceving 1)這是編碼風格的問題,但不,根據語言定義不需要。 2)同意,這些應該是本地的。 3)如你所說,退出*將*退出我的例子中的腳本。當然'exit'不會退出子shell,但這不是這個問題的具體問題。你不必使用'set -e',你只需要確保接收到錯誤,'MSG = $(foo ...)||死「的作品也是如此。 'set -e'是解決這個問題的一種方法[但它不是傻瓜式的](http://mywiki.wooledge.org/BashFAQ/105),我和其他許多人一樣,不推薦使用它。 –

4

該參數存儲在可擴展的$OPTARG中。

function t() { 
    echo $* 
    getopts "a:" OPTION 
    echo $OPTION 
    echo $OPTARG 
} 

輸出:

$ t -a bc 
-a bc 
a 
bc
+0

對不起,我錯誤地貼上我的代碼片段...我也呼應$ OPTARG,這是第3行是空白。任何其他想法? – Magnus

+0

@Magnus可能是因爲你多次調用函數,'$ OPTIND'沒有在本地定義(參見Adrian的回答)。雖然我很感激你接受了我的回答,但你應該寧願接受他的回答。 –

+0

該代碼僅在粘貼到shell時有效,但不在腳本中。 – kenorb

8

這裏是殼函數內getopts用法的簡單示例:

#!/usr/bin/env bash 
t() { 
    local OPTIND 
    getopts "a:" OPTION 
    echo Input: $*, OPTION: $OPTION, OPTARG: $OPTARG 
} 
t "[email protected]" 
t -a foo 

輸出:

$ ./test.sh -a bc 
Input: -a bc, OPTION: a, OPTARG: bc 
Input: -a foo, OPTION: a, OPTARG: foo 

作爲@Adrian pointed out,需要設置local OPTIND(或OPTIND=1)作爲殼不會自動重置OPTINDmultiple calls to getoptsman bash)之間。

的基本語法getopts是:

getopts OPTSTRING VARNAME [ARGS...] 

,默認情況下,不指定參數等同於用「$ @」,這是顯式調用它:getopts "a:" opts "[email protected]"

在問題的情況下,這些都是getopts所使用的變量進行檢查:

  • OPTIND - 要被處理的索引到下一個參數,
  • OPTARG - 變量設置爲任何參數用於選項getopts,
  • OPTERR(不是POSIX) - 設置爲0或1來指示Bash是否應顯示由getopts生成的錯誤消息。

進一步,請參閱:在Bash的黑客維基

+0

非常周到的佈局答案。我不知道它是否有效,但很好的工作。 – Drew