Поставьте команды в очередь, пока выполняется одна команда

Поставьте команды в очередь, пока выполняется одна команда

Предположим, вы запускаете команду, возврат которой занимает некоторое время, и хотите выполнить другую команду после ее выполнения, но вы не запланировали это заранее.

Я знаю, что есть возможность нажать Ctrl + Zи отправить fg && otherCommand. Однако, у этого варианта есть два существенных недостатка:

  1. Это не сработает, если первая команда представляет собой композицию разных команд ( command1 && command2или command1; command2), поскольку в этом случае последующие команды первой отправленной строки не будут выполнены.
  2. Выполнение первой команды останавливается, пока вы вводите следующую команду. С этими противными 30-секундными командами время, которое вы тратите на ввод следующей команды, составляет большую часть оставшегося времени выполнения, если не все.

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

  1. Это не сработает, если команда, которую вы выполняете первой, считывает данные из stdin.
  2. Если команда, которую вы выполняете первой, создает вывод, вы не сможете увидеть, что вы ввели.

Существует ли быстрый способ поставить в очередь несколько команд во время выполнения одной команды, возможно, с использованием специального эмулятора терминала или нескольких терминалов?

решение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 будет завершена в старой оболочке.

Связанный контент