Знание о том, когда bash завершил выполнение команды через FIFO-канал

Вопрос или проблема

Я пытаюсь связать веб-терминал с bash.

Моя текущая попытка сделать это заключается в создании оболочки, использующей FIFO-канал в качестве ввода, вот так:

Терминал 1

$ mkfifo pipe
$ bash <> pipe
file1    file2    file4

Терминал 2

$ echo "ls" > pipe

Как вы могли заметить, я получаю только ответы на команды, запуская оболочку в Терминале 1 (очевидно). Могу ли я определить, находится ли bash в простое время или нет? Мне нужно знать, когда показывать $PS1 на стороне клиента.

Если я выполняю что-то вроде apt-get install curl -y, команда выполняется непрерывно и завершается, когда завершится. Мне нужно знать, когда это завершится, чтобы на фронтенде я мог показать приглашение терминала.

Есть идеи?

Вы можете использовать другой канал, где bash (запущенный интерактивно) выводит ready, когда он готов, через $PROMPT_COMMAND:

$ mkfifo pipe ready
$ PS1= PS2= PROMPT_COMMAND='echo ready >&9' bash --norc --noediting -i <> pipe 9<> ready
done

В другом терминале:

$ read < ready
$ echo 'sleep 10; echo done' > pipe
$ if read < ready; then echo Ready to get more; else echo Terminated; fi
Ready to get more

Вместо вывода ready, вы могли бы выводить "$?" или "${PIPESTATUS[@]}", что позволило бы вам получить код завершения последней команды/конвейера в вашем другом терминале.

С опцией -i вы получаете интерактивную оболочку, в которой оболочка читает ~/.bashrc, выдает приглашение, и где readline используется для редактирования ввода, в результате чего вы видите эхо того, что напечатано (здесь отправлено через канал), все из чего не желательно здесь, поэтому мы отключаем их с помощью --norc, --noediting и устанавливаем строки приглашения Prompt Strings на пустые.

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

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

Ответ или решение

Чтобы определить, когда Bash завершает выполнение команды через FIFO (именованный канал), можно использовать подход с двумя FIFO каналами. Один канал будет использоваться для ввода команд в Bash, а другой — для получения уведомлений о том, что Bash готов принимать новые команды.

Вот шаги, которые помогут вам правильно настроить это взаимодействие.

Шаг 1: Создание FIFO каналов

В первом терминале создайте два FIFO канала:

$ mkfifo pipe ready

Шаг 2: Запуск Bash с использованием FIFO

Запустите Bash в интерактивном режиме, перенаправив его ввод и добавив специальную команду PROMPT_COMMAND, которая будет отправлять сообщение о готовности Bash:

$ PS1= PS2= PROMPT_COMMAND='echo ready >&9' bash --norc --noediting -i < pipe 9<> ready
  • PS1= и PS2= убирают приглашения командной строки, чтобы они не отображались.
  • PROMPT_COMMAND будет отправлять строку "ready" в административный FD 9, когда Bash завершает выполнение команды и готов принимать новую.
  • Опция --norc отключает загрузку конфигурационных файлов, такие как ~/.bashrc, что может быть полезно для предотвращения нежелательного поведения.
  • --noediting отключает режим редактирования команд, чтобы не возникали конфликты.

Шаг 3: Отправка команд

Во втором терминале отправляйте команды через канал:

$ read < ready  # Ожидайте, пока Bash будет готов
$ echo 'sleep 10; echo done' > pipe

Здесь сначала считывается готовность Bash, а затем отправляется команда, которую вы хотите выполнить.

Шаг 4: Ожидание завершения выполнения команды

После отправки команды вы можете снова считать с канала ready, чтобы узнать, завершилась ли команда. Если команда завершена, Bash отправит строку "ready":

$ if read < ready; then echo Ready to get more; else echo Terminated; fi
Ready to get more

Дополнительно: Обработка статуса последней команды

Чтобы получать статус выполнения последней команды, можно отправить "$?" или "${PIPESTATUS[@]}" в ready:

$ PROMPT_COMMAND='echo $? >&9' bash --norc --noediting -i < pipe 9<> ready

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

Заключение

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

Оцените материал
Добавить комментарий

Капча загружается...