同一程序的多個實例,獲取輸出
我在 Ubuntu 16.04 中有一個名為 的 shell 程序,
foo
當我按下任何按鈕時會輸出狀態更新。它位於 中/usr/local/bin/foo
,因此我可以在任何地方呼叫該程序。該程序的工作原理如下:$ foo Welcome
我按下一個鍵後,它會顯示:
Time now is 01:23:45
如果我按
Ctrl-C
,它將像大多數其他 shell 程序一樣退出。我希望這個
foo
程序在多個實例中執行。我知道 GNU Screen 命令可以在任務之間切換,但這樣做是正確的方法嗎?或者,我知道我可以讓程序在後台執行,如下所示:
$ foo & [1] 123456
Job ID 1 是在後台創建的,我可以通過它的 Job ID 呼叫它:
$ fg %1
但是,在獲得程序的最新輸出後,我需要將其放回後台(通過按任何按鈕:有什麼方法可以以程式方式執行此操作嗎?)。我怎樣才能做到這一點?
據我所知,您的要求是能夠:
- 同時執行程序的多個實例。
- 隨時獲得對任何實例的終端控制。
- 實例一輸出就發送回後台。
如果我們堅持這種
&
方法,那麼是的,(3) 有一個捷徑。當程序控制終端時,可以使用SIGTSTP
信號將其發送到後台。很方便,這通常是Ctrl
+Z
所做的。因此,您可能會有這樣的事情:
$ foo & Welcome [1] 10 $ foo & Welcome [2] 11 $ fg %1 <ENTER> Time now is 01:23:45 <Ctrl+Z> [1]+ Stopped
據我所知,沒有這樣的捷徑
fg
(你如何指出要帶回哪個實例?)請注意,
SIGTSTP
信號實際上並不需要來自啟動程序的 shell。如果你kill -TSTP
在第二個 shell 中通過 PID 處理,你也可以在第一個 shell 中取回它fg
。在獲得程序的最新輸出後,我需要將其放回後台(通過按任何按鈕:有什麼方法可以以程式方式執行此操作嗎?)
如果以程式方式表示您可以訪問
foo
的原始碼,那麼您可以使用我們剛剛看到的內容。raise
程序可以使用系統呼叫向自身發送信號。如果我們採用一個非常簡單的版本foo
,我們可以有這樣的東西:#include <stdio.h> #include <signal.h> int main(void) { printf("Welcome"); while(getchar()) { /* Use termios to switch to unbuffered mode */ fprintf(stdout, "The time is... something"); fflush(stdout); fflush(stdin); raise(SIGTSTP); } return 0; }
現在雖然這一切都相當不錯,但我同意這
screen
可能是完成這一切的更好方法,主要是因為您可以命名您的螢幕會話,因此永遠不需要記住作業或程序 ID。就像這種&
方法一樣,它還具有不需要更改原始碼的優點。$ screen -S foo1 $ ./foo Welcome <Ctrl-a d> [detached from 10.foo1] $ screen -s foo1 <ENTER> Time now is 01:23:45 <Ctrl-a d> [detached from 10.foo1]
這裡的另一個優點是您不需要在分離之前停止程序。如果您希望它在您不看的時候在後台做一些事情,那將非常方便。在以前的方法中,您需要在
bg
每次 stop 時執行foo
。您還可以使用 獲取正在執行的螢幕列表
screen -ls
。在我的機器上,我設置了一些別名~/.bashrc
來解決我的額外懶惰:alias S='screen -S' alias s='screen -r' alias sls='screen -ls'
這樣,您可以簡單地執行諸如
S foo1
,s foo1
, … 之類的操作,有些人可能會爭辯說,當您在命令中放錯空格或其他內容時,單字元別名可能會有點煩人,但我認為screen
這是其中一種非常方便的程序你有能力破例。現在假設您使用該
screen
方法,以下是如何將密鑰發送到會話並從 shell 獲取其最後一行輸出。有一些方法可以對此進行調整(我允許自己使用一些捷徑),但無論如何。您可以在 中定義以下函式~/.bashrc
:screen_key_tail() { screen -S $1 -X stuff "^M" tmp="$(mktemp)" screen -S $1 -X hardcopy "$tmp" grep -v ^$ "$tmp" | tail -n1 rm "$tmp" }
並呼叫它:
$ screen_key_tail foo1
您要定位
foo1
的會話的名稱在哪裡。screen