Shell

同一程序的多個實例,獲取輸出

  • July 13, 2018

我在 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

但是,在獲得程序的最新輸出後,我需要將其放回後台(通過按任何按鈕:有什麼方法可以以程式方式執行此操作嗎?)。我怎樣才能做到這一點?

據我所知,您的要求是能夠:

  1. 同時執行程序的多個實例。
  2. 隨時獲得對任何實例的終端控制。
  3. 實例一輸出就發送回後台。

如果我們堅持這種&方法,那麼是的,(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

引用自:https://unix.stackexchange.com/questions/455054