web-dev-qa-db-ja.com

すでに実行中のコマンドが終了した後にコマンドを実行するにはどうすればよいですか?

時間がかかるスクリプトを開始する場合、スクリプトを開始した後で必然的にそれを認識し、スクリプトが終了したら何らかの警告を表示する方法があったらいいのにと思います。

したがって、たとえば、私が実行した場合:

really_long_script.sh

enterキーを押します...完了後に別のコマンドを実行するにはどうすればよいですか?

35
mlissner

複数のコマンドを;で区切ることができるため、コマンドは順次実行されます。次に例を示します。

really_long_script.sh ; echo Finished

スクリプトがreturn-code 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は、&で開始した場合とほぼ同じように、バックグラウンドで実行します)

49
aland

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]としても表示されます。

14
Jaap Eldering

プロセスが現在のttyで実行されない場合は、次のことを試してください。

watch -g ps -opid -p <pid>; mycommand
13
Marinos An

これはそれほど難しいことではありません。既存のコマンドの実行中に次のコマンドをウィンドウに入力し、Enterキーを押すだけです。最初のコマンドが完了すると、2番目のコマンドが自動的に実行されます。

もっとエレガントな方法があると思いますが、これはうまくいくようです。

コマンドが完了した後にアラートを実行したい場合は、追加して編集します。これらのエイリアスを.bashrcに作成し、実行中にalertを実行できます。

 alias alert_helper='history|tail -n1|sed -e "s/^\s*[0-9]\+\s*//" -e "s/;\s*alert$//"'
 alias alert='notify-send -i gnome-terminal "Finished Terminal Job" "[$?] $(alert_helper)"'
2
mlissner

少し前に、別のプロセスの終了を待つスクリプトを作成しました。 DISPLAYが正しく設定されている場合、NOISE_CMDnotify-send ...のようになります。

#!/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を検索することに同意する場合は、興味深いかもしれません。

#!/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は私の目的にとって最もきれいで最も信頼できるものです。

1
Piscoris