Bagaimana menjalankan perintah setelah yang sudah berjalan, yang sudah ada selesai?

32

Jika saya memulai skrip yang akan memakan waktu lama, saya pasti menyadarinya setelah saya memulai skrip, dan berharap saya memiliki cara melakukan semacam peringatan setelah selesai.

Jadi, misalnya, jika saya menjalankan:

really_long_script.sh

dan tekan enter ... bagaimana saya bisa menjalankan perintah lain setelah selesai?

mlissner
sumber

Jawaban:

45

Anda dapat memisahkan beberapa perintah ;, sehingga dijalankan secara berurutan, misalnya:

really_long_script.sh ; echo Finished

Jika Anda ingin menjalankan program berikutnya hanya jika skrip selesai dengan kode-kembali 0 (yang biasanya berarti telah dijalankan dengan benar), maka:

really_long_script.sh && echo OK

Jika Anda menginginkan yang sebaliknya (yaitu hanya melanjutkan jika perintah saat ini gagal), daripada:

really_long_script.sh || echo FAILED

Anda bisa menjalankan skrip Anda di latar belakang (tapi waspadalah, skrip keluaran ( stdoutdan stderr) akan terus pergi ke terminal Anda kecuali Anda mengarahkannya ke suatu tempat), dan kemudian waituntuk itu:

really_long_script.sh &
dosomethingelse
wait; echo Finished

Jika Anda sudah menjalankan skrip, Anda dapat menangguhkannya dengan Ctrl-Z, dan kemudian jalankan sesuatu seperti:

fg ; echo Finished

Di mana fgmembawa proses yang ditangguhkan ke latar depan ( bgakan membuatnya berjalan di latar belakang, seperti memulai dengan &)

sebuah daratan
sumber
@mlissner Memperluas jawaban saya untuk membahas kasus ini
aland
8
Karena fgmengembalikan nilai pekerjaan yang diteruskannya, Anda dapat menggunakan fg && echo Finishedjika Anda ingin memastikan perintah berhasil sebelum menjalankan perintah lainnya.
palswim
13

Anda juga dapat menggunakan kontrol pekerjaan bash. Jika Anda mulai

$ really_long_script.sh

lalu tekan ctrl + z untuk menangguhkannya:

^Z
[1]+  Stopped                 really_long_script.sh
$ bg

untuk memulai kembali pekerjaan di latar belakang (seolah-olah memulai dengan really_long_script.sh &). Maka Anda bisa menunggu pekerjaan latar belakang ini dengan

$ wait N && echo "Successfully completed"

di mana N adalah ID pekerjaan (mungkin 1 jika Anda tidak menjalankan pekerjaan latar belakang lainnya) yang juga ditampilkan seperti di [1]atas.

Jaap Eldering
sumber
11

Jika proses tidak berjalan pada tty saat ini, maka coba ini:

watch -g ps -opid -p <pid>; mycommand
Marinos An
sumber
2
Saya suka penggunaan kreatif watch. Jawaban super singkat dan seseorang belajar cara baru yang bermanfaat untuk menggunakan arloji
Piotr Czapla
2

Ternyata ini tidak terlalu sulit: Anda cukup mengetik perintah berikutnya ke dalam jendela saat yang sudah ada berjalan, tekan enter, dan ketika yang pertama selesai, perintah kedua akan berjalan secara otomatis.

Saya menduga ada cara yang lebih elegan, tetapi ini tampaknya berhasil.

Mengedit untuk menambahkan bahwa jika Anda ingin menjalankan peringatan setelah perintah selesai, Anda dapat membuat alias ini di .bashrc, kemudian jalankan alertsaat sedang berjalan:

 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)"'
mlissner
sumber
7
Kecuali jika skrip yang berjalan mengharapkan input pada satu titik.
Daniel Beck
@Aniel - yeah ... itu masalah. Menembak.
mlissner
1

Beberapa waktu yang lalu saya telah menulis naskah untuk menunggu akhir dari proses lain. NOISE_CMDbisa jadi sesuatu seperti notify-send ..., mengingat yang DISPLAYdiatur dengan benar.

#!/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

Tanpa argumentasi apa pun, buat keributan segera. Perilaku ini memungkinkan sesuatu seperti ini untuk kenyamanan (katakan Anda memanggil skrip di bawah alarm.sh):

apt-get upgrade ; ~/bin/alarm.sh

Tentu saja Anda dapat melakukan banyak hal lucu dengan skrip seperti itu, seperti membiarkan instance alarm.shmenunggu instance alarm.sh, yaitu menunggu beberapa perintah lain. Atau menjalankan perintah tepat setelah beberapa tugas pengguna login lain selesai ...>: D

Versi sebelumnya dari skrip di atas mungkin menarik, jika Anda ingin menghindari ketergantungan pgrepdan menerima sendiri proses pencarian 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 "$@"

Sedikit di luar topik, tetapi berguna dalam situasi yang serupa: Orang mungkin tertarik reptyr, alat yang "mencuri" proses dari beberapa shell (induk) dan menjalankannya dari shell saat ini. Saya telah mencoba implementasi serupa dan reptyrmerupakan yang tercantik dan paling dapat diandalkan untuk keperluan saya.

Piscoris
sumber