28

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

Так, например, если я бегу:

really_long_script.sh

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

5 ответов5

39

Вы можете разделить несколько команд с помощью ; , поэтому они выполняются последовательно, например:

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 запускает его в фоновом режиме, почти так же, как и при запуске с &)

10

Вы также можете использовать контроль работы 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] выше.

8

Если процесс не запускается на текущем tty, то другим вариантом будет:

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

Некоторое время назад я написал скрипт для ожидания завершения другого процесса. NOISE_CMD может быть чем-то вроде notify 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 - самый красивый и самый надежный для моих целей.

1

Оказывается, это не так сложно: вы можете просто ввести следующую команду в окно, пока работает существующая, нажать клавишу ввода, и когда первая из них завершится, вторая команда автоматически запустится.

Я предполагаю, что есть более элегантные способы, но это, кажется, работает.

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

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .