2009-09-04 45 views
2

我將參數存儲在變量中的命令中。最後一個命令我想要的是:在bash變量內引用不受尊重

mock -r myconfig --define "debug_package %{nil}" --resultdir results --rebuild mypackage.src.rpm 

這裏是我的嘗試:

set -x # for debugging 

RESULTDIR=results 
MOCK_CONFIG="myconfig" 
MOCK_ARGS="-r $MOCK_CONFIG --define \"debug_package %{nil}\" --resultdir $RESULTDIR" 
cmd="mock $MOCK_ARGS --rebuild mypackage.src.rpm" 
$cmd 

的結果是:

+ RESULTDIR=results 
+ MOCK_CONFIG=myconfig 
+ MOCK_ARGS='-r myconfig --define "debug_package %{nil}" --resultdir results' 
+ cmd='mock -r myconfig --define "debug_package %{nil}" --resultdir results --rebuild mypackage.src.rpm' 
+ mock -r myconfig --define '"debug_package' '%{nil}"' --resultdir results --rebuild mypackage.src.rpm 
ERROR: Bad option for '--define' ("debug_package). Use --define 'macro expr' 

正如你所看到的,參數傳遞給--define參數沒有被正確引用。 --define認爲我只通過它debug_package,這是不完整的。

我在嘗試定義MOCK_ARGS時引號中的各種變體,甚至試圖擺脫debug_package%{nil}之間的空格。

什麼引號和/或轉義組合允許我構建這個參數列表並執行該腳本中的命令?

編輯:

我存儲在一個變量所得到的命令的原因是因爲它最終被傳遞到其中做了一些記錄的功能,然後執行該命令。

此外,我遇到this FAQ這表明我應該使用數組而不是變量。我已經開始嘗試數組,但到目前爲止還沒有一個可行的解決方案。

+0

這看起來像是http://stackoverflow.com/questions/954390/echo-nested-quotation-marks-in-tcsh的副本 – 2009-09-04 06:48:57

+0

http://stackoverflow.com/questions/954390/echo- nested-quotation-marks-in-tcsh不適用於我。 – 2009-09-04 07:18:26

+0

可能的重複[如何執行bash命令存儲爲帶有引號和星號的字符串](http://stackoverflow.com/questions/2005192/how-to-execute-a-bash-command-stored-as-a -string-with-quotes-and-asterisk) – 2015-07-05 08:37:28

回答

4

陣列是去爲這樣的事情的方式。以下是我想出了:

log_and_run() { 
    echo "$(date): running command: $*" 
    "[email protected]" 
    echo "$1 completed with status $?" 
} 

RESULTDIR=results 
MOCK_CONFIG="myconfig" 
MOCK_ARGS=(-r "$MOCK_CONFIG" --define "debug_package %{nil}" --resultdir "$RESULTDIR") 
cmd=(mock "${MOCK_ARGS[@]}" --rebuild mypackage.src.rpm) 
log_and_run "${cmd[@]}" 
# could also use: log_and_run mock "${MOCK_ARGS[@]}" --rebuild mypackage.src.rpm 

注意$ *擴展用空格(適合傳遞給一個日誌命令)分隔的所有參數;而「$ @」作爲單獨的單詞擴展爲所有參數(如在log_and_run中使用的,第一個將被視爲執行的命令,其餘爲參數)。類似地,「$ {MOCK_ARGS [@]}」擴展爲MOCK_ARGS的所有元素作爲單獨的單詞,不管它們是否包含空格(因此MOCK_ARGS的每個元素都成爲cmd的元素,沒有引號分析混淆)。

此外,我引用了MOCK_CONFIG和RESULTDIR的擴展;這裏沒有必要這樣做,因爲它們不包含空格,但是如果它們碰巧包含空格(例如,它是否從外部傳遞到腳本中,那麼它是很好的習慣),那麼您應該假設它可能包含空格) 。

順便說一句,如果您需要將其他參數傳遞給該函數(我將使用文件名的示例進行登錄),則可以使用array slicing僅拆分後面的參數,以用作記錄/執行:

log_and_run() { 
    echo "$(date): running command ${*:2}" >>"$1" 
    "${@:2}" 
    echo "$2 completed with status $?" >>"$1" 
} 
#... 
log_and_run test.log "${cmd[@]}" 

附錄:如果你想引用在日誌中包含的空間參數,可以在「手動」構建日誌字符串,做任何引用你想要的。例如:

log_and_run() { 
    local log_cmd="" 
    for arg in "[email protected]"; do 
     if [[ "$arg" == *" "* || -z "$arg" ]]; then 
      log_cmd="$log_cmd \"$arg\"" 
     else 
      log_cmd="$log_cmd $arg" 
     fi 
    done 
    echo "$(date): running command:$log_cmd" 
    ... 

注意,這將處理在參數和空白參數空間,而不是(例如)內部參數雙引號。這樣做「正確」可以任意複雜...

此外,我構造log_cmd字符串的方式,它與一個前導空間;我通過在echo命令中省略之前的空間來處理上述情況。如果您需要實際修剪空間,請使用"${log_cmd# }"

+0

謝謝,這解決了我的問題!天才的中風是讓一個完整的「模擬」命令成爲一個陣列。這導致了我的'log_and_run()'函數的重構,它天真地使用'$ 1'來記錄和運行命令而不是'$ *'和/或'$ @'。我無法得到''debug_package%{nil}「'的引號出現在日誌中,但這是我可以忍受的一個小細節。 – 2009-09-06 09:30:43

4

Shell腳本可能很糟糕。在很多情況下,cmd="blah $blah";$cmdblah $blah不同。您可以嘗試eval $cmd而不是$ cmd。

嘗試調用此perl腳本,而不是模擬:

#!/usr/bin/perl 
print join("\n",@ARGV),"\n"; 

你可能會驚訝地看到參數列表居然是:

-r 
myconfig 
--define 
"debug_package 
%{nil}" 
--resultdir 
results 
--rebuild 
mypackage.src.rpm 

雖然我猜「設置-x」輸出試圖用單引號向你展示這一點。

一個好的技巧我最近了解到的情況是

function f { 
    echo "[email protected]" 
} 

其實正確轉發位置參數到f($*沒有)。

它看起來像 「EVAL」 帶給你的,你可能打算:

set -x # for debugging 
RESULTDIR=results 
MOCK_CONFIG="myconfig" 
MOCK_ARGS="-r $MOCK_CONFIG "'--define "debug_package %{nil}" --resultdir '"$RESULTDIR" 
cmd="mock $MOCK_ARGS --rebuild mypackage.src.rpm" 
echo $cmd 
eval $cmd 

輸出:

+ echo mock -r myconfig --define '"debug_package' '%{nil}"' --resultdir results --rebuild mypackage.src.rpm 
mock -r myconfig --define "debug_package %{nil}" --resultdir results --rebuild mypackage.src.rpm 
+ eval mock -r myconfig --define '"debug_package' '%{nil}"' --resultdir results --rebuild mypackage.src.rpm 
++ mock -r myconfig --define 'debug_package %{nil}' --resultdir results --rebuild mypackage.src.rpm 
-r 
myconfig 
--define 
debug_package %{nil} 
--resultdir 
results 
--rebuild 
mypackage.src.rpm 
+2

謝謝 - eval是我的快速解決方案。 – 2011-09-10 23:56:53