從腳本執行時後台作業終止,但從 bash 提示符執行時工作正常
我在 MacOS 10.9.4 上。我想將 sftp 放到後台,以便稍後通過命名管道自動將一些文件推送到它,如此處所建議的。當我從 bash 提示符手動輸入命令時它工作正常(
cat
為簡單起見用作偵聽器作業):$ mkfifo test $ cat > test & [1] 60765 $ cat test | cat & [2] 60781 60782 [1] + 60765 suspended (tty input) cat > test $ echo works! > test works! $ ps -ax | grep 60765 60765 ttys023 0:00.00 cat 60900 ttys023 0:00.00 grep 60765
但是,當我將其放入 bash 腳本時,它會停止工作:
$ cat test.sh mkfifo test1 cat > test1 & echo $! cat test1 | cat & $ bash test.sh 60847 $ echo fails > test1 ^C% $ ps -ax | grep 60847 60882 ttys023 0:00.00 grep 60847
據我了解,這裡的問題是,
cat > test1 &
從提示符執行時該行工作正常,但從腳本執行時以某種方式終止,因此我的偵聽器作業收到 EOF 並也終止。我在這裡缺少什麼,我怎樣才能使它從腳本中工作?
編輯:我面臨的實際問題是這個。對於開發,我必須將程式碼部署到遠端伺服器。為此,我使用了 rsync,為了稍微自動化,我使用fswatch來監聽文件夾中的文件更改,並在更改發生時執行 rsync。
$ fswatch -0 . | while read -d "" event; do rsync ./ {remote folder} done
它工作得很好,直到我嘗試在具有大延遲的慢速連接上使用它。Rsync 每次打開新的 ssh 連接並發現文件差異,這在慢速連接上需要時間。我試圖通過打開與 sftp 的持久連接並將其推送到僅更改的文件(我從 fswatch 收到的名稱)來解決此問題。為此,我需要一種方法來啟動 sftp 程序並稍後在 fswatch 事件發生時向其發送命令。我發現了這個問題,但是寫到 /proc/{pid}/fd/0 並不認為可以在 mac 上工作,所以我試圖使用命名管道來回答。我可以
cat > test1 &
在啟動 fswatch 腳本之前手動執行,所以這實際上可以工作。但我想要一個可靠的解決方案,以便能夠將此腳本提供給我的同事。
所有這些都與後台程序嘗試從終端讀取時發生的情況有關。預設情況下,只允許活動程序組從終端讀取。如果活動程序組之外的程序嘗試從終端讀取,則會發送信號以暫停該程序,直到它被 shell 喚醒。
在您的第一個範例中,您將啟動兩個程序組。每個都在後台啟動,因此不允許從終端讀取。
cat > test &
將嘗試立即從終端讀取並暫停。但是,bash
僅在顯示下一個提示之前才會通知您,因此您必須在收到通知之前鍵入另一個命令。您的
echo
命令寫入由第二個程序組(未掛起)讀取的管道。在該序列結束時,第一個cat
命令保持掛起狀態,並且再也沒有被喚醒。在您的第二個範例中,整個腳本在單個程序組中執行。因此,此時您
cat
在一個程序組中有三個不同的命令,其中一個在從終端讀取時被阻止。然後您返回到初始bash
shell,因此必須暫停執行緒組。此外,從您的初始
bash
shell 的角度來看,該執行緒組已經終止,因為它看到了bash
您鍵入的第二個命令終止。最初的bash
shell 不知道子程序產生了大子程序,並且其中一個被阻止從終端讀取。當腳本的程序組不再受初始
bash
shell 控制時,第一個cat
命令將在其輸入中獲取 EOF。此時所有cat
命令將看到一個空輸入並立即完成處理。