![Как выполнить команду после завершения уже работающей?](https://rvso.com/image/1289035/%D0%9A%D0%B0%D0%BA%20%D0%B2%D1%8B%D0%BF%D0%BE%D0%BB%D0%BD%D0%B8%D1%82%D1%8C%20%D0%BA%D0%BE%D0%BC%D0%B0%D0%BD%D0%B4%D1%83%20%D0%BF%D0%BE%D1%81%D0%BB%D0%B5%20%D0%B7%D0%B0%D0%B2%D0%B5%D1%80%D1%88%D0%B5%D0%BD%D0%B8%D1%8F%20%D1%83%D0%B6%D0%B5%20%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0%D1%8E%D1%89%D0%B5%D0%B9%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 — идентификатор задания (вероятно, 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
и согласиться на поиск идентификаторов процессов самостоятельно:
#!/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
это самая красивая и надежная для моих целей.