2016-09-14 28 views
0

的命令時錯誤:括號子shell不工作存儲在一個變量

(echo: command not found 

代碼:

input="(echo 1)" 
$input 

爲什麼它不評估括號以同樣的方式,把它放在當我這樣稱呼它的時候是一個子殼?

+1

參見[BashFAQ#50](HTTP:// mywiki.wooledge.org/BashFAQ/050)。一個沒有引號的擴展只經過兩個解析階段(場分割和全局擴展);這是非常好的理由(否則在bash中編寫安全代碼會更困難)。鏈接的常見問題解答詳細介紹,包括討論最佳實踐,以便您可能想將代碼存儲在變量中。 –

+4

您不能將這些命令放入變量中。事實上,將命令放在變量中很容易失敗。變量包含_data_,而不是_命令!_如果您想將命令存儲在某處以備將來使用,請使用_function._ –

+1

順便說一句,您的代碼和錯誤不會對齊。如果你使用了這裏提供的確切代碼,你會得到'(:command not found')。確保將你的問題中的代碼完全複製/粘貼到問題*中,以避免將來出現這種情況,這些差異實際上可能很重要 –

回答

0

括號是shell語法。

要將反映爲將變量存儲在shell中進行處理的語法,必須使用eval命令。

僅將變量值插入命令行不會觸發eval語法評估。這將是eval的不必要的入侵,這會導致各種問題。

例如,考慮一下:

arg="(parenthesized)" 
somecommand $arg 

我們只是想somecommand與字符串(parenthesized)作爲它的參數來調用;我們不想運行子shell。這種隱含的評估會將無害的數據轉化爲實時代碼,從而產生安全漏洞,更不用說編碼噩夢來試圖避免它。

$arg的處理規則與位置無關;膨脹發生即使$arg是在命令行的第一個元素相同的方式:

$arg foo 

參數替換變成$arg到文本(parenthesized),然後被試圖作爲一個命令,而不是作爲一個殼的語法。

要執行的一塊存儲在input shell腳本,使用:

eval "$input" 

你也可以做這樣的:

input="echo 1"  # no parentheses 

/bin/sh -c "$input" # run in subshell explicitly 

當然,子shell辦法飼料的代碼片段執行周圍腳本的同一個shell,而在這裏我們選擇了可能與調用shell不同的/bin/sh,或者即使它是符號鏈接到同一個shell也具有不同的行爲。

+0

由於'command'是一個內建函數,所以用它來代替some-random-other-command有點混亂 –

+0

@CharlesDuffy先生,這是一個很好的觀點,它必須是固定的。 – Kaz

1

這在BashFAQ #50中詳細討論。

未引用的擴展只經歷了兩個shell解析階段:字段拆分和glob擴展。因此,(echo 1)首先被分成字段:(,echo,1);每個擴展爲一個glob(模擬,因爲它們都不是glob擴展);然後將它們作爲命令運行:調用(,第一個參數爲echo,第二個參數爲1,第三個參數爲)

正確的方式來存儲的代碼是在一個函數:

# best-practices approach 
input() (echo 1;) 
input 

...或者,如果你想使之更加明確到人的讀者,你真的一個子shell和間沒有」使用括號而非括號牛逼的錯誤或習慣:

# same, but more explicit about intent 
input() { (echo 1); } 
input 

...如果無法實現,可以使用eval(但要注意在BashFAQ #48給出警告的):

# avoid this approach if at all possible 
input="(echo 1)" 
eval "$input" 

如果你在一個字符串建立一個命令的真正原因是參數化的內容,而是基於一個數組:

input_args=(1)     # define an array 
input() (echo "${input_args[@]}") # use that array in a function (if needed) 

# add things according to conditional logic as appropriate 
if ((2 > 1)); then 
    input_args+=("possible argument here") 
fi 

# call the function, or just use the array directly, such as: (echo "$(input_args[@]}") 
input