2012-08-28 76 views
6

我想在一個循環中創建bash別名,循環是從命令讀取行。爲了逐行讀取輸出,我相信我需要將輸出傳送到read。但是,當我這樣做時,別名就不存在了。爲什麼我不能在一個while循環中進行評估?

如果我包括我的.bashrc如下:

for x in a1 a2; do 
    eval "alias $x='echo foo'" 
done 

echo -e "a3\na4" | while read x; do 
    eval "alias $x='echo foo'" 
done 

別名a1a2存在,但a3a4沒有。這兩個循環之間有什麼區別?

+0

這是管道到'while'循環時很常見的問題。見[這個答案](http://stackoverflow.com/questions/7612320/bash-weird-variable-scope-when-populating-array-with-results/7612420#7612420),或[BashFAQ/024](http: //mywiki.wooledge.org/BashFAQ/024)瞭解詳情和各種替代解決方案。 –

+5

另外,沒有必要在這裏使用'eval'。 '別名$ x ='echo foo''將在定義別名之前展開'$ x'。 – chepner

回答

5

問題在於管線。在形式爲a | b | c的流水線中,每個單獨的命令a,bc在單獨的子shell中運行,這意味着它接收到父母的執行環境(包括別名)的副本,並且任何改變它製作自己的副本(例如通過運行alias)將不會影響父母[ ref]。

在你的情況,你可以通過書面形式解決這個問題:

while read x; do 
    eval "alias $x='echo foo'" 
done < <(echo -e "a3\na4") 

仍然將運行在一個子shell echo -e "a3\na4",但將運行在正常/父執行環境while -loop。

+0

我以前沒見過'<(command)'語法。是創建一個指向'command'輸出的文件描述符嗎? –

+0

@JeffKlukas:是的;它被稱爲「流程替換」(請參閱​​http://www.gnu.org/software/bash/manual/bashref.html#Process-Substitution),它使用FIFO或'/ dev/fd'文件。文檔暗示它不適用於所有系統,但它適用於我嘗試過的所有系統,包括Cygwin。 – ruakh

6

管道中的while循環運行在子shell中。你可以這樣做:

while read x; do 
    eval "alias $x='echo foo'" 
done << EOF 
a3 
a4 
EOF 
3

在bash 4.2和更高版本,您可以設置lastpipe選項,以防止管道的最後命令在一個子shell執行。工作控制也必須關閉(set +m)才能使其工作。

shopt -s lastpipe 
set +m 
echo -e "a3\na4" | while read x; do 
    alias $x='echo foo' 
done 
+0

+1:很高興知道! – ruakh

相關問題