2014-01-13 76 views
5

我調試用shell腳本的古怪,不知道我是否誤解了bash的「叉」(&)是如何工作的,也許是因爲我通常是在單一命令中使用它通過一個終端,如:當我在Bash腳本中使用帶`&的函數時會發生什麼?

[~me]$ someExecutable & 

現在,在shell腳本:

foo() { 
    echo "logic" 
} 

bar() { 
    echo "idic" 
} 

baz() { 
    echo "katra" 
} 

foo & 
bar 
baz 

我的目的是爲功能foo進行異步調用,然後對腳本的剩餘部分繼續在原來的進程上下文中執行。

當我執行這個示例腳本我獲得預期的輸出:

logic 
idic 
katra 

(即,barbaz唯一的單視電話;我不是在所有的相對困擾訂單的三行輸出,據我瞭解可能會有所不同)

但我可能會誤解輸出和腳本本身。如果是這樣,那肯定會解釋我在真實代碼中看到的怪異現象,並且不需要進一步挖掘。

是否有可能的是,在子進程中,調用foo後,分叉的shell腳本會繼續嗎?這意味着我的shell腳本的其餘部分將被執行兩次

當我在Bash腳本中使用&時,發生了什麼?

回答

3

的符號只分叉()在您的示例調用FOO。它不會分解整個腳本。只有foo()運行在單獨的線程中,當foo()完成時退出。 bar()和baz()繼續在同一個線程中運行

+0

謝謝 - 這就是我以後的! –

+4

+1解決問題的核心。 Quibble:foo()運行在一個(異步)* subshel​​l *中,這是一個獨立的*進程*。 – mklement0

1

&字符告訴shell在後臺執行一個命令(或一組命令)。

下一命令立即執行。

沒有兩次執行腳本的危險,所以它是比C的fork()在這方面有所不同。

2

bash中的&不是分支。 它會告訴Bash在子shell啓動命令,並繼續解析爲其他命令(而不是等待該命令完成)。

因此,如您所料,它會在後臺運行'foo',並繼續處理頂級shell中的'bar'和'baz'命令。發生調用shell沒有分叉,但'foo'在後臺運行。

因此,「foo」的輸出實際上可能發生在bar或baz之後,具體取決於其內容......但由於它使用「echo」(這是shell內置),到「foo」後臺進程設置時,「回聲」立即可用:因此,在調用shell傳遞給下一個命令之前,您可能會看到它的輸出,這顯然是您的情況。 (但YMMV!如果「foo」正在調用一個沉重的外部命令,很可能它的輸出將在稍後發生)

在終端中,它幾乎是一回事:您可以考慮一個帶shell提示符的終端窗口作爲文件腳本shell,即登錄shell正在閱讀「鍵入它時」。行爲幾乎相同。

+0

我對輸出的順序並不感興趣,只有三行。 –

+0

與在終端中鍵入它相同。但我猜你已經注意到了:)這一切都發生了:'&'不是一個分支,即它不分叉調用shell(或者更確切地說是shell +腳本)。 shell在單獨的進程中產生命令,然後在後臺處理它,而不是在繼續之前等待它完成。 Ref http://web.mit.edu/gnu/doc/html/features_5.html –

+0

複製該內容。這意味着我對這些年來的直覺是正確的,但是我的原始錯誤仍然是無法解釋的:( –

1

除了一個事實,即&導致命令控制操作員可以在子shell 1異步執行的,你可以利用Coprocesses來控制輸出。

而是說調用函數的:

foo & 

說:

coproc fubar { foo; } 

,然後說讀取輸出:

cat <&"${fubar[0]}" 

這也將允許你控制輸出(是否需要在之類的其他功能之後或之前發射) 210或baz)。


例如,以下內容:

foo() { 
    echo "logic1" 
    echo "logic2" 
} 

bar() { 
    echo "idic" 
} 

baz() { 
    echo "katra" 
} 

coproc fubar { foo; } 
bar 
baz 
cat <&"${fubar[0]}" 

會產生:

idic 
katra 
logic1 
logic2 
+0

雖然OP的問題沒有直接解決,但最好了解coprocesses(bash 4+)。 – mklement0

0

其實這個命令並運行你的函數foo的背景:

foo & 

但是,您輸入的時間和baz foo已經完成其運行並將其輸出打印在您的終端上。

但是,如果您運行的功能,如這點,你會發現其中的差別:

foo & bar; baz 
[1] 46453 
idic 
katra 
logic 
[1]+ Done     foo 

這裏您的進程ID可能比我的不同,但你可以看到,logic打印在年底的其它輸出後2個功能。

+0

我並不關心輸出的順序;這是_only_'foo'在後臺運行,而不是分叉整個腳本。 –

+0

不,我不是在強調命令,我僅僅是指出函數'foo'確實在後臺調用,'bar','baz'被正常調用,這就是爲什麼輸出順序發生了變化。 – anubhava

+0

我知道'foo'在後臺運行,但我想確保子進程只會運行'foo',而不是繼續執行腳本的其餘部分(導致腳本的其餘部分運行兩次) –

相關問題