Сценарий, использующий fifos, не генерирующий выход при обработке из stdin

Я пытаюсь использовать именованные каналы для параллельной обработки отдельных входных данных, прежде чем объединять результаты. У меня было что-то работающее, пока я не добавил возможность ввода данных из stdin (после этого ответа ).

Здесь я сообщаю о своей проблеме, используя упрощенный пример, который просто выбирает столбцы и больше не обрабатывает перед вставкой, но фактический скрипт делает больше, чем это.

  • Выполнять команды из истории, которые соответствуют регулярному выражению или grep
  • Вставка переменной Bash - Perl Script
  • разница между «ls -alR /» и «ls -alR / &»?
  • Накопительное время CPU (столбец времени в команде o / p команды ps aux)
  • Заголовок окна в X показывает неправильное имя приложения
  • найти команду с помощью квантификатора regex, например {1,2}
  • Пример данных:

    $ cat data.txt A1 A2 A3 A4 A5 B1 B2 B3 B4 B5 C1 C2 C3 C4 C5 D1 D2 D3 D4 D5 E1 E2 E3 E4 E5 F1 F2 F3 F4 F5 G1 G2 G3 G4 G5 H1 H2 H3 H4 H5 I1 I2 I3 I4 I5 J1 J2 J3 J4 J5 K1 K2 K3 K4 K5 L1 L2 L3 L4 L5 

    Сценарий с использованием обычных файлов:

     $ cat test_files.sh #!/bin/bash get_1() { cut -f1 - > ${1} } get_3() { cut -f3 - > ${1} } get_5() { cut -f5 - > ${1} } setup() { workdir=$(mktemp -d) col1="${workdir}/col1.txt" col3="${workdir}/col3.txt" col5="${workdir}/col5.txt" } setup cleanup() { rm -rf ${workdir} } if [ $# -ge 1 -a -f "${1}" ] then cat ${1} \ | tee >(get_1 ${col1}) \ | tee >(get_3 ${col3}) \ | get_5 ${col5} \ || { echo "cat failed" && cleanup && exit 1; } else cat - \ | tee >(get_1 ${col1}) \ | tee >(get_3 ${col3}) \ | get_5 ${col5} \ || { echo "cat failed" && cleanup && exit 1; } fi paste ${col1} ${col3} ${col5} cleanup exit 0 

    Это хорошо работает в обоих режимах:

     $ ./test_files.sh data.txt A1 A3 A5 B1 B3 B5 C1 C3 C5 D1 D3 D5 E1 E3 E5 F1 F3 F5 G1 G3 G5 H1 H3 H5 I1 I3 I5 J1 J3 J5 K1 K3 K5 L1 L3 L5 $ cat data.txt | ./test_files.sh A1 A3 A5 B1 B3 B5 C1 C3 C5 D1 D3 D5 E1 E3 E5 F1 F3 F5 G1 G3 G5 H1 H3 H5 I1 I3 I5 J1 J3 J5 K1 K3 K5 L1 L3 L5 

    Вот версия с использованием fifos, где я выполняю извлечение столбцов в фоновом режиме и вставляю из fifos:

     $ cat test_fifos.sh #!/bin/bash get_1() { cut -f1 - > ${1} } get_3() { cut -f3 - > ${1} } get_5() { cut -f5 - > ${1} } setup() { workdir=$(mktemp -d) col1="${workdir}/col1.txt" mkfifo ${col1} col3="${workdir}/col3.txt" mkfifo ${col3} col5="${workdir}/col5.txt" mkfifo ${col5} } setup cleanup() { rm -rf ${workdir} } if [ $# -ge 1 -a -f "${1}" ] then cat ${1} \ | tee >(get_1 ${col1}) \ | tee >(get_3 ${col3}) \ | get_5 ${col5} \ || { echo "cat failed" && cleanup && exit 1; } & else cat - \ | tee >(get_1 ${col1}) \ | tee >(get_3 ${col3}) \ | get_5 ${col5} \ || { echo "cat failed" && cleanup && exit 1; } & fi paste ${col1} ${col3} ${col5} cleanup exit 0 

    Он работает при вводе входного файла в качестве аргумента:

     $ ./test_fifos.sh data.txt A1 A3 A5 B1 B3 B5 C1 C3 C5 D1 D3 D5 E1 E3 E5 F1 F3 F5 G1 G3 G5 H1 H3 H5 I1 I3 I5 J1 J3 J5 K1 K3 K5 L1 L3 L5 

    Но, беря данные из stdin, нет выхода:

     $ cat data.txt | ./test_fifos.sh $ # Nothing here, no error message 

    Выполняя некоторые эксперименты для создания минимального примера, я понял, что код для обработки возможных ошибок, похоже, является частью проблемы. Вот версия с использованием fifos и не пытающаяся обрабатывать ошибки:

     $ cat test_fifos_noerr.sh #!/bin/bash get_1() { cut -f1 - > ${1} } get_3() { cut -f3 - > ${1} } get_5() { cut -f5 - > ${1} } setup() { workdir=$(mktemp -d) col1="${workdir}/col1.txt" mkfifo ${col1} col3="${workdir}/col3.txt" mkfifo ${col3} col5="${workdir}/col5.txt" mkfifo ${col5} } setup cleanup() { rm -rf ${workdir} } if [ $# -ge 1 -a -f "${1}" ] then cat ${1} \ | tee >(get_1 ${col1}) \ | tee >(get_3 ${col3}) \ | get_5 ${col5} & else cat - \ | tee >(get_1 ${col1}) \ | tee >(get_3 ${col3}) \ | get_5 ${col5} & fi paste ${col1} ${col3} ${col5} cleanup exit 0 

    Это работает в обоих режимах:

     $ ./test_fifos_noerr.sh data.txt A1 A3 A5 B1 B3 B5 C1 C3 C5 D1 D3 D5 E1 E3 E5 F1 F3 F5 G1 G3 G5 H1 H3 H5 I1 I3 I5 J1 J3 J5 K1 K3 K5 L1 L3 L5 $ cat data.txt | ./test_fifos_noerr.sh A1 A3 A5 B1 B3 B5 C1 C3 C5 D1 D3 D5 E1 E3 E5 F1 F3 F5 G1 G3 G5 H1 H3 H5 I1 I3 I5 J1 J3 J5 K1 K3 K5 L1 L3 L5 

    Почему нет вывода, когда я обрабатываю возможные ошибки и использую fifos, беря данные из stdin?


    Изменить: некоторая отладка

    Я добавил некоторые отладочные выходные данные в сценарий сбоя:

     $ cat test_fifos.sh #!/bin/bash get_1() { >&2 echo "get_1" cut -f1 - > ${1} } get_3() { >&2 echo "get_3" cut -f3 - > ${1} } get_5() { >&2 echo "get_5" cut -f5 - > ${1} } setup() { workdir=$(mktemp -d) col1="${workdir}/col1.txt" mkfifo ${col1} col3="${workdir}/col3.txt" mkfifo ${col3} col5="${workdir}/col5.txt" mkfifo ${col5} } setup cleanup() { >&2 echo "cleanup" rm -rf ${workdir} } if [ $# -ge 1 -a -f "${1}" ] then >&2 echo "then" cat ${1} \ | tee >(get_1 ${col1}) \ | tee >(get_3 ${col3}) \ | get_5 ${col5} \ || { >&2 echo "cat failed" && cleanup && exit 1; } & else >&2 echo "else" cat - \ | tee >(get_1 ${col1}) \ | tee >(get_3 ${col3}) \ | get_5 ${col5} \ || { >&2 echo "cat failed" && cleanup && exit 1; } & fi >&2 echo "before paste" paste ${col1} ${col3} ${col5} >&2 echo "after paste" cleanup exit 0 

    Вот что происходит, когда данные считываются из stdin:

     $ cat data.txt | ./test_fifos.sh else before paste get_3 get_5 get_1 after paste cleanup 

    Таким образом, это означает, что ветка else выполняется.

  • Как вы можете передавать параметры для работы в скрипте?
  • Как случайным образом изменить фоновое изображение Gnome с помощью bash?
  • Извлечь имя группы из `id` и сохранить ее в переменной
  • Bash для преобразования всех * flac в * .mp3 с FFmpeg?
  • comm сбой при вводе переменной bash
  • Что делают скрипты в файле /etc/profile.d?
  • One Solution collect form web for “Сценарий, использующий fifos, не генерирующий выход при обработке из stdin”

    Проблема с использованием & для запуска команд в фоновом режиме заключается в том, что оболочка автоматически закрывает stdin для этой команды. Итак, ваша cat - сразу читает конец файла. В качестве обходного пути вы можете дублировать файловый дескриптор от 0 до 3, например, и использовать это:

     ... else exec 3<&0 cat - <&3 \ | tee >(get_1 ${col1}) \ ... 
    Linux и Unix - лучшая ОС в мире.