остановка записи записи без остановки остальной части скрипта

#bash

#bash

Вопрос:

Я играю со скриптами, которые используют API преобразования речи в текст Google. Для API требуются файлы в кодировке flac, поэтому записывающая часть скрипта выглядит следующим образом:

 arecord -q -t wav -d 0 -f S16_LE -r 16000 | flac - -f --best --sample-rate 16000 -s -o "$TEMP_FILE"
  

Эта команда будет записывать до тех пор, пока пользователь не завершит работу с помощью ctrl-c, и записанный формат wav должен быть передан в программу flac для вывода в формате flac, затем сценарий должен продолжаться.

Проблема, с которой я сталкиваюсь, заключается в том, что нажатие ctrl-c полностью завершает сценарий и отключает часть звука (файл flac все еще выводится). Если я запускаю скрипт без канала:

 arecord -q -t wav -d 0 -f S16_LE -r 16000 some.wav
  

Затем нажатие ctrl-c только завершит запись и продолжит работу со скриптом, как и должно быть.

Как мне исправить это, чтобы ctrl-c останавливал только команду arecord и позволял завершить остальную часть скрипта (включая передаваемую по каналу кодировку flac)?

Ответ №1:

Мне кажется, то, что вы пытаетесь сделать, не может быть выполнено.

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

Суть:

  • Нажатие Ctrl-C во время выполнения конвейера отправляет сигнал SIGINT ВСЕМ процессам в конвейере.
  • Порядок, в котором процессы получают сигнал, не гарантируется.
  • Если ВСЕ процессы в конвейере не перехватят сигнал, сценарий будет прерван в целом (хотя сам скрипт может перехватить сигнал с помощью trap команды — но такая ловушка оболочки не будет выполняться до того, как процессы конвейера получат сигнал и, как правило, будут завершены им).

В вашем конкретном случае, arecord предназначен для захвата SIGINT и выхода упорядоченным образом в ответ.
В отличие от этого, flac похоже, что нет — он завершается принудительно.
Однако, даже если flac также была выполнена ловушка SIGINT для завершения работы, учитывая недетерминированный порядок, в котором сигнал принимается задействованными процессами, вы не можете безопасно использовать конвейер с Ctrl-C, ожидая, что общая обработка завершится упорядоченным образом.

(В качестве отступа: arecord сообщает код выхода 1 при завершении с помощью Ctrl-C, что заставляет меня задуматься, как вы можете отличить это от истинного сбоя, такого как нехватка места на диске.)

Таким образом:

  • Вызвать arecord как отдельную команду и записать выходные данные во (временный) файл.
  • После передайте (временный) файл в flac (и удалите временный файл, когда закончите).

Комментарии:

1. Вы можете выполнить killall arecord , чтобы завершить процесс чисто.

2. @PoundHash, предпосылка вопроса заключается в том, что нажата Ctrl-C, которая отправляет SIGINT всем процессам в конвейере. killall отправляет SIGTERM по умолчанию, что может или не может (точно так же, как SIGINT ) привести к чистому завершению: это зависит от того, предназначен ли данный целевой процесс для обработки этого сигнала.

Ответ №2:

Я попробую этот способ:

 # Create a fifo
FIFO=/tmp/my_fifo
mkfifo $FIFO

# Start arecord in background and redirect its output into the fifo
arecord ... > $FIFO amp;

# Get the arecord PID
PID=$!

# Trap the SIGINT to send SIGINT to arecord
trap "kill -INT $PID" INT

# Start flac and redirect its input with the fifo.
flac - ... < $FIFO

# The script should be blocked here, and a CTRL C will run
# the kill -INT to the arecord process only.
# But I don't know how flac will react after ...
# If flac exit correctly, just restore the SIGINT
trap - INT
  

Комментарии:

1.Проблема в том, что Ctrl-C убивает flac , потому что flac не предназначен для чистого завершения таким образом (в отличие от arecord ). Что необходимо, так это способ перехватить Ctrl-C до того, как он достигнет flac , чего ваше решение не делает (ловушка срабатывает после flac того, как она уже уничтожена) — и я бы не знал, как это сделать в bash. Кроме того, мне интересно, является ли то, что нужно для операции, элегантностью одного конвейера. Если это невозможно сделать, тогда просто записывайте во временное значение. сначала файл, а затем перекодирование временного значения. файл намного проще.