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
私が理解する限り、あなたの要件は次のとおりです。
- プログラムの複数のインスタンスを同時に実行します。
- いつでもすべてのインスタンスの端末制御を取得します。
- インスタンスがそれを出力した直後にバックグラウンドに戻ります。
このアプローチに固執するなら、&
そうです。 (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 -TSTP
2番目のシェルが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
ターゲットにしたいセッションの名前はどこにありますかfoo1
?screen