web-dev-qa-db-ja.com

別のスクリプト内のスクリプトを停止する方法

端末エミュレータを使用して、Ubuntu 16.04を実行しています。

2つのスクリプトがあります:a.shb.sha.shb.shを呼び出します。

a.sh

echo "a is running"
sleep 5s
bash b.sh
sleep 5s
echo "a is still running"

b.sh

echo "b is now running"
sleep 1000s
echo "Bananas"

a.shを実行し、完了する前に(バナナを出力する前に)b.shを停止し、a.shを最後まで実行して「a is still running」と出力する方法はありますか?

pkill -f b.sha.shの中に入れてみましたが、a.shが完了する前にb.sha.shの両方が停止しました。

5
speld_rwong

ある時点で、あなたはあなたが望んでいるように見えるものに近くなりました。

a.sh

#!/bin/sh

echo "a.sh running"
sleep 10s
(sleep 10s; pkill -f b.sh) &
bash b.sh
sleep 10s
pkill -f b.sh
echo "a.sh still running"

b.sh(あなたのバージョンと同じ)

echo "b is now running"
sleep 1000s
echo "Bananas"

(sleep 10s; pkill -f b.sh) &a.sh行は、10秒間スリープしてからb.shを強制終了するサブシェルを作成します。次に、そのサブシェルをバックグラウンドに配置するため、a.shは実行を継続できます。次に、a.shb.shを実行し、sleep 1000sが実行されます。 10秒後、サブシェルのsleep 10sが終了し、それ(サブシェル)がpkill -f b.shを実行して、b.shプロセスを終了します。 a.shが実行を再開します。 pkill -f b.shプロセスはすでに終了しているため、2番目のb.shは何もしません。

これは実行時に何が起こるかです:

$ ./a.sh
a.sh running #すぐ
 bが実行中です #上記の約10秒後
 ./ a.sh:6行目:13684終了bash b.sh #上記の約10秒後
 a.shはまだ実行中です #上記の約10秒後#上記の直後

これには、a.shがすぐに終了すると、b.shがすぐに実行を再開できるという利点があります。 b.shが10秒以上実行された場合にのみ、pkillがキックします。他の回答では、sleepの前にpkillが時間を費やす間、a.shがすでに終わっていても、b.shはアイドル状態である必要があります。


別のユーザー 投稿 コメント (現在削除済み)と言っています

私は得る

./a.sh
a.sh running
b is now running
Terminated

あなたが報告するものではありません。何か案が?

暗くて嵐の夜でした。突然、ショットが鳴った!

暗い嵐の夜、スヌーピーでした チャールズM.シュルツ

pgrepおよびpkillの引数は正規表現です。具体的には、拡張正規表現1catcutを同時に実行してみてください2。次に、pgrep c.tを実行します— 2つのPIDがリストされます。pscatcutであることを確認できます。

私が言ったことをexactlyした場合、あなたは本当に私がしたのと同じ結果を得るべきでした。しかし、私はあなたが別のことをした42のZorkmidsを賭けてもかまいません。あなたのどちらか:

  1. a.shの代わりに#!/bin/bashをシバン(最初の行)として#!/bin/shを開始した、または
  2. a.shの代わりにbash a.sh./a.shを実行しました。

突然、ショットが鳴った!

b.shは、bの後に任意の文字が続き、shが続く正規表現です。自分自身(b.sh)、およびb!shb~shb&shb7shbushなどにも一致します。そして……(それを待つ)……また、bashにも一致します。

したがって、pkill -f b.shは、すべてのbashプロセスと、b.shが名前に含まれている他のプロセスを強制終了します。私が実行したものを実行したとき、私のログインシェル(少なくとも部分的にpkillの影響を受けません)はbashでしたが、a.sh/bin/shで実行されていました(ただし、b.shbashで実行されていました)。 pkill -f b.shコマンドは、bothbashbash b.shが含まれているため、b.shプロセスを強制終了しました。しかし、/bin/shを実行していたa.shは影響を受けませんでした。

あなたがそれを私があなたがそれを実行したと私が思う方法で実行したと仮定すると(2つの選択肢のいずれか)、allスクリプトプロセスはbashを実行していました。そのため、pkill -f b.shコマンドはスクリプトが処理するallを強制終了しました。

pkill -f b.shpkill -f 'b\.sh'に変更し(ドットをエスケープしてonlyドットに一致させ、文字は一致させない)、正しい結果が得られるはずです。
________
1pgrep(1)
2 2つのターミナル(シェルウィンドウ)がある場合は、どちらかでcat | cut -f1(ターミナルからの入力を使用)を実行し、もう一方でp- commandsを実行します。端末が1つしかない場合は、sleep 42 | cat | cut -f1 &を実行し(sleepを使用しないと、パイプラインはすぐに折りたたまれます)、同じウィンドウでp- commandsを実行します。

この線:

bash b.sh

b.shスクリプトが終了するまで待機します。b.shにはコントロールがないため、a.shが終了する前にスクリプトで何かを行う方法はありません。

b.shスクリプトをバックグラウンドにしてa.shに制御を戻すには、次のようなものを使用します。

bash b.sh &

これにより、コントロールがすぐにa.shに戻り、次のようなスクリプトを作成できます。

#!/bin/bash 

echo "a is running"
sleep 1s
bash b.sh &
sleep 2
pkill -f 'b\.sh'
sleep 1s
echo "a is still running"

スクリプトb.shは次のようになります:

#!/bin/bash
echo "b is now running"
sleep 1000s
echo "Bananas"

実行すると、次のようになります。

$ ./a.sh
a is running
b is now running
./a.sh: line 7:  8424 Terminated              bash b.sh
a is still running

「ジョブ制御メッセージ」を回避するには、サブシェルを使用し、bash b.sh &を次のように変更します。

(bash b.sh &)

そして、実行すると、次のようになります。

$ ./a.sh
a is running
b is now running
a is still running

編集:

報告した「終了した」応答の問題は、投稿したpkillコマンドがpkill -f b.shが引数を正規表現として使用していることです。その正規表現は、bに続けて任意の文字.に続けてshに一致します。これは、実行を開始したプログラムであるa.shという名前の「bash」と一致し、a.shが終了する理由を説明します。 pkillコマンドを次のように変更します。

pkill -f 'b\.sh'

一致する正規表現がプレーン文字列「b.sh」であることを確認します。

これを配置すると、pkillが一致するプロセスを確認できます。

ps -f -o pid,cmd,args |grep 'b.sh'

スキルの直前。

これをgrep 'b\.sh'に変更して、実際には1つのPIDのみに一致することを確認します。

2
Isaac

a.shスクリプトは、b.shスクリプトをバックグラウンドジョブとして実行して、スクリプトを途中で終了させる必要があります。

b.shはバックグラウンドジョブとして実行されるため、そのプロセスID(PID)にアクセスできます。つまり、killを使用してシグナルを送ることができます。これは、pkillを使用するよりも安全です。これは、指定したパターンに一致する他のプロセスにシグナルを送る可能性があります。

a.shで次のことができます。

#!/bin/sh

echo "A: I'm alive!"
./b.sh & bpid=$!

echo 'A: Sleeping for a short while'
sleep 2

echo 'A: Signalling B'
kill "$bpid"

echo "A: I'm done here"

$!は、最後に開始されたバックグラウンドタスクのPIDに展開されます。

b.shの例:

#!/bin/sh

echo "B: I'm alive!"

echo 'B: Sleeping for longer than A does'
sleep 10

echo "B: I'm done here"

それを実行する:

$ ./a.sh
A: I'm alive!
A: Sleeping for a short while
B: I'm alive!
B: Sleeping for longer than A does
A: Signalling B
A: I'm done here

b.shは、sleepの呼び出しが完了するまで実際に終了しない場合があることに注意してください。これは、bashdashzshおよびpdkshの場合ですが、ksh93b.shが終了する場合)の場合は該当しませんすぐに)。

0
Kusalananda