Linux

從腳本執行時後台作業終止,但從 bash 提示符執行時工作正常

  • September 13, 2014

我在 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在一個程序組中有三個不同的命令,其中一個在從終端讀取時被阻止。然後您返回到初始bashshell,因此必須暫停執行緒組。

此外,從您的初始bashshell 的角度來看,該執行緒組已經終止,因為它看到了bash您鍵入的第二個命令終止。最初的bashshell 不知道子程序產生了大子程序,並且其中一個被阻止從終端讀取。

當腳本的程序組不再受初始bashshell 控制時,第一個cat命令將在其輸入中獲取 EOF。此時所有cat命令將看到一個空輸入並立即完成處理。

引用自:https://serverfault.com/questions/628320