#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. Кроме того, мне интересно, является ли то, что нужно для операции, элегантностью одного конвейера. Если это невозможно сделать, тогда просто записывайте во временное значение. сначала файл, а затем перекодирование временного значения. файл намного проще.