![すでに実行中の既存のコマンドが終了した後に、別のコマンドを実行するにはどうすればよいでしょうか?](https://rvso.com/image/1289035/%E3%81%99%E3%81%A7%E3%81%AB%E5%AE%9F%E8%A1%8C%E4%B8%AD%E3%81%AE%E6%97%A2%E5%AD%98%E3%81%AE%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%81%8C%E7%B5%82%E4%BA%86%E3%81%97%E3%81%9F%E5%BE%8C%E3%81%AB%E3%80%81%E5%88%A5%E3%81%AE%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%82%92%E5%AE%9F%E8%A1%8C%E3%81%99%E3%82%8B%E3%81%AB%E3%81%AF%E3%81%A9%E3%81%86%E3%81%99%E3%82%8C%E3%81%B0%E3%82%88%E3%81%84%E3%81%A7%E3%81%97%E3%82%87%E3%81%86%E3%81%8B%3F.png)
長時間かかるスクリプトを開始すると、スクリプトを開始した後に必ずそのことに気づき、終了したら何らかのアラートを出す方法があればいいのにと思うことになります。
たとえば、次のように実行します。
really_long_script.sh
Enter キーを押します...完了したら別のコマンドを実行するにはどうすればよいでしょうか?
答え1
複数のコマンドを で区切って;
、順番に実行することができます。例:
really_long_script.sh ; echo Finished
スクリプトが戻りコード 0 で終了した場合にのみ次のプログラムを実行する場合 (通常は、スクリプトが正しく実行されたことを意味します)、次のようにします。
really_long_script.sh && echo OK
逆のこと(つまり、現在のコマンドが失敗した場合にのみ続行する)をしたい場合は、次のようにします。
really_long_script.sh || echo FAILED
スクリプトをバックグラウンドで実行することもできます (ただし、スクリプトの出力 (stdout
およびstderr
) は、どこかにリダイレクトしない限り、引き続きターミナルに送信されることに注意してください)。その後、wait
次のようにします。
really_long_script.sh &
dosomethingelse
wait; echo Finished
すでにスクリプトを実行している場合は、 を使用してスクリプトを一時停止しCtrl-Z
、次のようなコマンドを実行できます。
fg ; echo Finished
fg
中断されたプロセスをフォアグラウンドに移動する場所(bg
開始時とほぼ同じように、バックグラウンドで実行されるようになります&
)
答え2
プロセスが現在の tty で実行されない場合は、次を試してください。
watch -g ps -opid -p <pid>; mycommand
答え3
bashのジョブ制御も使用できます。
$ really_long_script.sh
次に、Ctrl + Z を押して一時停止します。
^Z
[1]+ Stopped really_long_script.sh
$ bg
ジョブをバックグラウンドで再開します( で開始した場合と同様really_long_script.sh &
)。その後、このバックグラウンドジョブを待機するには、
$ wait N && echo "Successfully completed"
ここで、N はジョブ ID (他のバックグラウンド ジョブを実行していない場合はおそらく 1) であり、[1]
上と同じように表示されます。
答え4
少し前に、別のプロセスの終了を待つスクリプトを作成しました。が正しく設定されていれば、NOISE_CMD
のようなものになります。notify-send ...
DISPLAY
#!/bin/bash
NOISE_CMD="/usr/bin/mplayer -really-quiet $HOME/sfx/alarm-clock.mp3"
function usage() {
echo "Usage: $(basename "$0") [ PROCESS_NAME [ PGREP_ARGS... ] ]"
echo "Helpful arguments to pgrep are: -f -n -o -x"
}
if [ "$#" -gt 0 ] ; then
PATTERN="$1"
shift
PIDS="$(pgrep "$PATTERN" "$@")"
if [ -z "$PIDS" ] ; then
echo "No process matching pattern \"$PATTERN\" found."
exit
fi
echo "Waiting for:"
pgrep -l "$PATTERN" "$@"
for PID in $PIDS ; do
while [ -d "/proc/$PID" ] ; do
sleep 1
done
done
fi
exec $NOISE_CMD
引数なしで、ただちにノイズを出します。この動作により、次のようなことが可能になります (以下のスクリプトを呼び出すとしますalarm.sh
)。
apt-get upgrade ; ~/bin/alarm.sh
もちろん、このようなスクリプトでは、 のインスタンスを、他のコマンドalarm.sh
を待っている のインスタンスまで待たせるなど、さまざまな面白いことができますalarm.sh
。または、ログインしている他のユーザーのタスクが終了した直後にコマンドを実行することもできます... >:D
pgrep
プロセス ID への依存を回避し、プロセス ID を自分で検索することを受け入れたい場合は、上記のスクリプトの以前のバージョンが興味深いかもしれません。
#!/bin/bash
if [ "$#" -lt 2 -o ! -d "/proc/$1" ] ; then
echo "Usage: $(basename "$0") PID COMMAND [ ARGUMENTS... ]"
exit
fi
while [ -d "/proc/$1" ] ; do
sleep 1
done
shift
exec "$@"
少し話題から外れますが、似たような状況で役立つもの:reptyr
は、ある(親)シェルからプロセスを「盗み」、現在のシェルからそれを実行するツールです。私は同様の実装を試しましたが、これがreptyr
私の目的にとって最も美しく、最も信頼性が高いものでした。