複数のコマンドを実行し、bashでそれらを殺します


52

単一のシェルで複数のコマンド(プロセス)を実行したい。それらはすべて独自の連続出力を備えており、停止しません。バックグラウンドでそれらを実行すると壊れますCtrl- C。それらをすべてCtrl-で停止できるように、単一のプロセス(サブシェル、多分?)として実行したいと思いCます。

具体的には、単体テストmocha(監視モード)を実行し、サーバーを実行してファイルの前処理(監視モード)を実行し、1つのターミナルウィンドウでそれぞれの出力を確認します。基本的に、タスクランナーの使用を避けたいと思います。

バックグラウンドでプロセスを実行することで実現できますが(&)、その後、それらを停止するにはフォアグラウンドに配置する必要があります。それらをラップするプロセスが欲しいのですが、プロセスを停止すると、その「子」が停止します。


同時に実行する必要がありますか、または次々に実行する必要がありますか
ミニックス

はい、プロセスは同時に実行する必要がありますが、各プロセスからの出力を確認する必要があります。
user1876909

回答:


67

コマンドを同時に実行するには、&コマンド区切り記号を使用できます。

~$ command1 & command2 & command3

これが開始さcommand1れ、バックグラウンドで実行されます。と同じcommand2です。その後、command3正常に起動します。

すべてのコマンドの出力は文字化けしますが、それが問題にならない場合は、解決策になります。

後で出力を個別に見たい場合は、各コマンドの出力をにパイプして、出力teeをミラーリングするファイルを指定できます。

~$ command1 | tee 1.log & command2 | tee 2.log & command3 | tee 3.log

出力はおそらく非常に乱雑になります。これに対抗するために、を使用してすべてのコマンドの出力にプレフィックスを付けることができますsed

~$ echo 'Output of command 1' | sed -e 's/^/[Command1] /' 
[Command1] Output of command 1

したがって、すべてをまとめると、次のようになります。

~$ command1 | tee 1.log | sed -e 's/^/[Command1] /' & command2 | tee 2.log | sed -e 's/^/[Command2] /' & command3 | tee 3.log | sed -e 's/^/[Command3] /'
[Command1] Starting command1
[Command2] Starting command2
[Command1] Finished
[Command3] Starting command3

これは、おそらくあなたが見ているものの非常に理想的なバージョンです。しかし、それは私が今考えることができる最高です。

すべてを一度に停止する場合は、のビルドを使用できますtrap

~$ trap 'kill %1; kill %2' SIGINT
~$ command1 & command2 & command3

これが実行されますcommand1command2、バックグラウンドでとcommand3あなたがそれを殺すことができますフォアグラウンドにCtrl+ C

あなたが最後のプロセスを強制終了する場合Ctrl+ 私たちはINTerupt信号の受信とその実行を接続しているため、コマンドが実行され、事が押して送信される+を。Ckill %1; kill %2CtrlC

それぞれ、1番目と2番目のバックグラウンドプロセス(your command1command2)を強制終了します。を使用してコマンドを終了したら、忘れずにトラップを削除してくださいtrap - SIGINT

コマンドの完全なモンスター:

~$ trap 'kill %1; kill %2' SIGINT
~$ command1 | tee 1.log | sed -e 's/^/[Command1] /' & command2 | tee 2.log | sed -e 's/^/[Command2] /' & command3 | tee 3.log | sed -e 's/^/[Command3] /'

もちろん、画面を見ることができます。コンソールを必要な数の個別のコンソールに分割できます。したがって、すべてのコマンドを個別に監視できますが、同時に監視できます。


3
すべての批判を楽しみにしています。:)
Minix

2
ありがとうございました。それはまさに私が望んだことを行います(トラップコマンド)。ただし、ソリューションは再利用性のためにスクリプトでラップする必要があります。
user1876909

@ user1876909これはスケルトンです。詳細はあなた次第です[1]。お役に立てて嬉しいです。[1] pastebin.com/jKhtwF40
Minix

3
これはかなり賢い解決策です。ivは何か新しいことを学びました。ブラボー+1
mike-m

1
これは素晴らしいです。この答えから掘り下げて学ぶことがたくさんあります。
ccnokes

20

同じプロセスグループ内で(およびそれらだけ)実行するように手配すると、一度に多数のプロセスを簡単に強制終了できます。

Linuxは、setsid新しいプロセスグループでプログラムを実行するためのユーティリティを提供します(新しいセッションでも、私たちは気にしません)。(これは実行可能ですが、なしではより複雑setsidです。)

プロセスグループのプロセスグループID(PGID)は、グループ内の元の親プロセスのプロセスIDです。プロセスグループ内のすべてのプロセスを強制終了するには、負のPGIDをkillシステムコールまたはコマンドに渡します。このPIDを持つ元のプロセスが停止しても、PGIDは有効なままです(ただし、少し混乱する可能性があります)。

setsid sh -c 'command1 & command2 & command3' &
pgid=$!
echo "Background tasks are running in process group $pgid, kill with kill -TERM -$pgid"

非対話型シェルからバックグラウンドでプロセスを実行する場合、それらはすべてシェルのプロセスグループに残ります。バックグラウンドプロセスが独自のプロセスグループで実行されるのは、対話型シェルのみです。したがって、フォアグラウンドに残っている非対話型シェルからコマンドを分岐すると、Ctrl+ Cはそれらをすべて強制終了します。wait組み込みコマンドを使用して、すべてのコマンドが終了するまでシェルを待機させます。

sh -c 'command1 & command2 & command3 & wait'
# Press Ctrl+C to kill them all

2
減速されていない答え(一番下の方法)。理解し、暗記するのは簡単。
ニコラスマーシャル

14

これがまだここにないことに驚いていますが、私のお気に入りの方法は、バックグラウンドコマンドでサブシェルを使用することです。使用法:

(command1 & command2 & command3)

両方からの出力が表示され、すべてのbashコマンドと便利な機能が引き続き使用可能で、1回ですべてが削除されますCtrl-c。通常、これを使用してライブデバッグクライアントファイルサーバーとバックエンドサーバーを同時に起動するため、必要に応じて両方を簡単に強制終了できます。

これが機能する方法は、ということですcommand1し、command2新しいサブシェルインスタンスのバックグラウンドで実行され、command3そのインスタンスのフォアグラウンドにあり、サブシェルが最初からキル信号を受信するものであるCtrl-c打鍵。これは、誰がどのプロセスを所有し、いつバックグラウンドプログラムが強制終了されるかに関して、bashスクリプトを実行することに非常に似ています。


wait最後のコマンド(この例ではcommand3)として追加すると、ユーザーがCtrl-cを押した後にクリーンアップコードを実行できます。
dotnetCarpenter

0

セミコロン;または次の&&ように使用できます。

cmd1; cmd2   # Runs both the commands, even if the first one exits with a non-zero status.

cmd1 && cmd2 # Only runs the second command if the first one was successful.

それはコマンドを同時に実行しません。
ジル「SO-悪であるのをやめる」

-2

を使用できますpipe。これにより、パイプの両端でコマンドが同時に開始されます。すべてのコマンドを停止することもできCTRL-Cます。

1st command | 2nd command | 3rd command

コマンドを次々に実行したい場合は、@ serenesatのメソッドを使用できます。


これは、最初のコマンドの出力を2番目のコマンド(など)に渡します。これは、最初のコマンドの出力が最終的に端末で行われることになっているため、ここでは適切ではありません。
ジル「SO-悪であるのをやめる」
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.