Як запустити команду після вже запущеної, існуючої закінчується?


32

Якщо я запускаю сценарій, який триватиме тривалий час, я неминуче усвідомлюю його після запуску сценарію, і хочу, щоб у мене був спосіб зробити якесь попередження, коли воно закінчиться.

Так, наприклад, якщо я запускаю:

really_long_script.sh

і натисніть клавішу Enter ... як я можу запустити іншу команду після її завершення?

Відповіді:


45

Можна відокремити кілька команд за допомогою ;, тому вони виконуються послідовно, наприклад:

really_long_script.sh ; echo Finished

Якщо ви бажаєте виконати наступну програму лише у тому випадку, якщо сценарій закінчено кодом return 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змушує його запускатись у фоновому режимі, дуже схоже на розпочате &)


@mlissner Розширив свою відповідь, щоб висвітлити цю справу
аланд

8
Оскільки fgповертає значення завдання, яке воно поновлює, ви можете використовувати його, fg && echo Finishedякщо хочете переконатися, що команда успішна перед виконанням іншої команди.
palswim

13

Ви також можете використовувати контроль роботи 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 - ідентифікатор завдання (можливо, 1, якщо ви не виконували жодних інших фонових завдань), який також відображається як [1]вище.


11

Якщо процес не працює на поточному tty, спробуйте це:

watch -g ps -opid -p <pid>; mycommand

2
Я люблю творче використання watch. Супер коротка відповідь, і ви дізнаєтесь новий корисний спосіб використання годинника
Piotr Czapla

2

Виявляється, це не так складно: Ви можете просто ввести наступну команду у вікно, поки існуюча працює, натисніть клавішу enter, а коли перша закінчиться, друга команда автоматично запуститься.

Я здогадуюсь, є більш елегантні способи, але це, здається, працює.

Редагуючи, щоб додати, що якщо ви хочете запустити попередження після завершення команди, ви можете створити ці псевдоніми в .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)"'

7
Якщо тільки запущений сценарій не очікує введення в один момент.
Даніель Бек

@Daniel - так ... це проблема. Стріляти.
mlissner

1

Нещодавно я написав сценарій, щоб дочекатися закінчення іншого процесу. 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і прийняти самостійно шукати ідентифікатори процесу:

#!/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є найкрасивішим та найнадійнішим у своїх цілях.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.