
Предположим, вы запускаете команду, возврат которой занимает некоторое время, и хотите выполнить другую команду после ее выполнения, но вы не запланировали это заранее.
Я знаю, что есть возможность нажать Ctrl + Zи отправить fg && otherCommand
. Однако, у этого варианта есть два существенных недостатка:
- Это не сработает, если первая команда представляет собой композицию разных команд (
command1 && command2
илиcommand1; command2
), поскольку в этом случае последующие команды первой отправленной строки не будут выполнены. - Выполнение первой команды останавливается, пока вы вводите следующую команду. С этими противными 30-секундными командами время, которое вы тратите на ввод следующей команды, составляет большую часть оставшегося времени выполнения, если не все.
Я также знаю, что вы можете просто ввести следующую команду, пока выполняется одна команда, а затем нажать, Enterчтобы отправить ее. Однако, это также имеет два основных недостатка:
- Это не сработает, если команда, которую вы выполняете первой, считывает данные из
stdin
. - Если команда, которую вы выполняете первой, создает вывод, вы не сможете увидеть, что вы ввели.
Существует ли быстрый способ поставить в очередь несколько команд во время выполнения одной команды, возможно, с использованием специального эмулятора терминала или нескольких терминалов?
решение1
Нажмите Ctrl+ Zи немедленно запустите bg
. Это заставит текущую команду продолжать работать в фоновом режиме. Затем вы можете использовать fg && otherCommand
для планирования otherCommand
после текущей.
Чтобы упростить задачу, я настроил Ctrl+ Zв своей оболочке на запуск bg
при нажатии на пустую командную строку. СмотритеКак в zsh можно быстрее отказаться от процесса переднего плана?иКак отправить приложения командной строки непосредственно в фоновый режим?; Я не проверял, позволяют ли современные версии bash сделать то же самое.
решение2
Вы можете создать именованный канал (это нужно сделать один раз):
mkfifo ~/myfifo
Затем с терминала (назовем его терминалом А) вы можете сказать:
exec 10< ~/myfifo
Чтобы назначить конец чтения канала файловому дескриптору 10, можно использовать любое другое число больше 2 (чтобы стандартный ввод, вывод и ошибка оставались доступными, если они понадобятся другой команде).
Затем с другого терминала (назовем его терминалом B) вы можете сказать:
cat - > ~/myfifo
Для завершения подключения к терминалу A, который затем возвращает приглашение. Эта команда записывает то, что вы вводите из стандартного ввода в конвейер. Затем вы можете ввести следующее в терминал A:
while read -u10 -r LINE; do eval "$LINE"; done
Таким образом, он выполнит команды, которые вы вводите в терминале B. read
Команда прочитает строки из файлового дескриптора 10 и выполнит их с помощью eval
. eval
позволяет вам запускать команды оболочки, такие как экспорт переменных.
Пока терминал A открыт, вы можете прервать цикл с помощью сочетания клавиш Ctrl+C, чтобы снова ввести команды, а затем перезапустить цикл, чтобы начать выполнение оставшихся команд в очереди.
Команды exec и while можно поместить в скрипт оболочки, чтобы можно было использовать Ctrl-Z fg && yourscript
для активации режима конвейера, если вы забыли сделать это в начале.
решение3
Скорее всего, вы хотите:
wait $pid
Если вы не работаете в той же оболочке, вы не сможете использовать встроенную функцию и вам понадобится обходной путь. Смотрите обсуждениездесь.
решение4
РЕДАКТИРОВАТЬ:Я неправильно понял вопрос, но описанная ниже методика все равно может быть полезна людям при запуске команд в скрипте bash (чтобы у них был один PID)
Вот что я использую (в Linux), когда command1 выводит полезный вывод, и я просто хочу запустить другой процесс в другой оболочке после его завершения (то есть я не хочу переводить command1 в фоновый режим):
tail --pid=$command1_pid -f /dev/null; command2
где $command1_pid
находится PID процесса, завершения которого вы ждете?
(Кажется, я изначально нашел это здесь:https://stackoverflow.com/a/41613532/1676393. Смотрите там другие полезные подробности. Например, версию, которая будет работать на Darwin (macOS))
Шаг за шагом:
- остановить команду1 с помощью Ctrl+Z
- запустить
ps
, затем найти процесс, соответствующий команде 1, и найти его PID - затем перезапустите процесс command1, введя
fg
, и в новой оболочке выполните указанную выше команду
Таким образом, команда 2 будет запущена в новой оболочке, когда команда 1 будет завершена в старой оболочке.