同じプログラムの複数のインスタンス、出力を取得する

同じプログラムの複数のインスタンス、出力を取得する

fooいずれかのボタンを押すとステータスアップデートを出力するUbuntu 16.04というシェルプログラムがあります。/usr/local/bin/fooどこでもプログラムを呼び出すことができるように配置されています。プログラムの仕組みは次のとおりです。

$ foo
Welcome

キーを押すと、次のように表示されます。

Time now is 01:23:45

を押すと、Ctrl-C他のほとんどのシェルプログラムのように終了します。

fooこのプログラムを複数のインスタンスで実行したいと思います。 GNU Screenコマンドがタスク間で切り替えることができることを知っていますが、これは正しい方法ですか?

または、次のようにプログラムをバックグラウンドで実行できることを知っています。

$ foo &
[1]  123456

ジョブID 1はバックグラウンドで生成され、そのジョブIDで呼び出すことができます。

$ fg %1

ただし、プログラムの最新の出力を取得したら、それをバックグラウンドにしておく必要があります(任意のボタンを押す必要があります。プログラムでこれを行う方法はありますか?)。この目標をどのように達成できますか?

答え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実際にプロセスを開始したシェルから出る必要はありません。kill -TSTP2番目のシェルがPIDを介して処理している場合は、1fg番目のシェルでも復元できます。

プログラムの最新の出力を取得したら、それをバックグラウンドに戻す必要があります。 (任意のボタンを押す必要があります。プログラムでこれを行う方法はありますか?)

合格するとプログラム的に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するたびに実行する必要がありましたfoo

を使用して実行中の画面のリストを取得することもできますscreen -ls。私のコンピュータでは、追加~/.bashrcの怠惰を説明するためにいくつかのエイリアスを設定しました。

alias S='screen -S'
alias s='screen -r'
alias sls='screen -ls'

S foo1この方法を使用すると、... のような作業を簡単に実行できます。s foo1一部の人々は、コマンドでスペースや他の項目を誤って配置すると、単一文字のエイリアスが少し迷惑になる可能性があると主張するかもしれませんが、screenこれはそのようなプログラムの1つだと思います。とても便利ですあなたは例外を作成する能力があります。

今、このアプローチを取ると仮定すると、screenキーをセッションに送信し、シェルから最後の出力行を取得する方法は次のとおりです。これを調整する方法はいくつかあります(いくつかのショートカットを使用できるようにしました)。しかし、何でも可能です。次の関数を定義できます~/.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

ターゲットにしたいセッションの名前はどこにありますかfoo1screen

関連情報