2012-07-10 47 views
3

這是試圖簡化我遇到的問題。 我定義它設置一個變量的函數,這個工作在這樣的場景:當它是管道的一部分時,Bash函數失敗

$ function myfunc { res="ABC" ; } 
$ res="XYZ" 
$ myfunc 
$ echo $res 
    ABC 

所以資源已被調用改爲MYFUNC。但是:

$ res="XYZ" 
$ myfunc | echo 
$ echo $res 
    XYZ 

所以當MYFUNC是管道的價值不會改變的一部分。 即使涉及管道,我如何使myfunc以我所希望的方式工作?

(在真實腳本「MYFUNC」做了更詳細的課程和管道的另一端有一個zenity進步的對話,而不是一個毫無意義的回聲)

感謝

+2

也許'myfunc |在新進程中調用echo',而在第一種情況下,當前調用'myfunc'? – cnicutar 2012-07-10 08:02:38

回答

4

這是不可能的在Unix上。爲了更好地理解這一點,你需要知道變量是什麼。 Bash使用所有已定義的變量保留兩個內部表。一個用於當前shell的局部變量。您可以使用set name=valuename=value創建這些文件。這些過程是本地的;它們在創建新流程時不會被繼承。

要將變量導出到新的子進程,必須使用export name將其導出。這告訴bash「我希望孩子們看到這個變量的價值」。這是一項安全功能。

當你在bash中調用一個函數時,它在當前shell的上下文中執行,所以它可以訪問和修改所有的變量。

但管道是與I/O管道連接的進程列表。這意味着你的函數在一個shell中執行,並且只有這個shell的輸出可見到echo

即使在myfunc出口將不起作用,因爲出口僅適用於通過在那裏你做了出口和echo是由相同的外殼開始作爲myfunc外殼啓動的進程:

bash 
+-- myfunc 
+-- echo 

echomyfunc的子女。

解決方法:

  1. 寫的變量到一個文件
  2. 使用更復雜的輸出格式,如XML或數行的將輸出的第一行始終是變量和實際產出來自於未來線。
+0

謝謝亞倫。我會標記爲已回答 – Thorsen 2012-07-10 08:10:48

4

正如@Aaron說,該問題是通過在一個子shell運行功能引起的。但爲了避免這種在bash,使用代替管工藝替代辦法:

myfunc > >(echo) 

這確實太大的管會同樣的事情,但在MYFUNC主殼,而不是一個子進程運行。請注意,這是一個只有bash的特徵,你必須使用#!/斌/ bash作爲你的家當這個工作。

+0

謝謝戈登。這看起來很有趣。我以前沒有聽說過過程替換。對於像我這樣無知的人,http://tldp.org/LDP/abs/html/process-sub.html似乎是一個有用的資源。 – Thorsen 2012-07-12 11:18:04