распределять вывод через FIFO

распределять вывод через FIFO

Я пытаюсь распределить очень длинный вывод make, используя следующий метод

mkfifo myfifo 
make 2>&1 | tee myfifo | grep -E "errors|warnings" myfifo > errors.log | cat myfifo

Идея состоит в том, что часть вывода должна копироваться в файлы журналов, а весь вывод перенаправляться в стандартный вывод консоли.

Сначала вроде бы работает, но потом внезапно останавливается и зависает, пока я не нажму Ctrl-Z.

Использование замещения процесса

make 2>&1 | tee >(grep -E "errors|warnings" > errors.log)

невозможно, так как оболочка скомпилирована со строгим соответствием POSIX по умолчанию.

платформа - дистрибутив на основе Ubuntu. shell bash 4.2 (и только один доступен)

решение1

Что

make 2>&1 | tee myfifo | grep -E "errors|warnings" myfifo > errors.log | cat myfifo
          P1           P2                                              P3

команда не имеет особого смысла. Она запускает эти 4 команды одновременно с трубами между ними:

  • make 2>&1: stdout и stderr идут в P1
  • tee myfifo: stdin из P1, stdout в P2. Поэтому teeзаписывает вывод и в P2 myfifo, и в P2.
  • grep -E "errors|warnings" myfifo > errors.log: stdin из P2, но вы передаете имя файла ( myfifo) grep, поэтому grepне будет считывать его со stdin. stdout идет в errors.log, ничего не пишется в P3
  • cat myfifo: stdin из P3, но снова, поскольку catзадано имя файла, он читает его вместо этого. Так что оба grepи catчитаются myfifoодновременно.

Так как ничего не читается из P2, teeзависнет, когда P2 заполнится. Также catне будет отображаться часть, myfifoкоторая была прочитана grep.

make 2>&1 | tee myfifo | grep -e errors -e warnings > errors.log | cat myfifo

ближе к тому, что вы имели в виду, я думаю. Опять же, P3 не используется, но мы используем для одновременного |запуска catи ждем его.

Или вы можете сделать следующее:

make 2>&1 | tee myfifo & grep -e errors -e warnings > errors.log
wait

Если вам нужно больше greps, вам нужно больше fifo:

make 2>&1 | tee fifo2grep1 fifo2grep2 &
grep errors fifo2grep1 > errors.log &
grep warnings fifo2grep2 > warnings.log
wait

В системах, поддерживающих /dev/fd/x, вы также можете сделать:

make 2>&1 | { tee /dev/fd/3 | grep -e errors -e warnings 3>&-; } 3>&1

(именно это обычно и делает подстановка процессов в оболочках, которые ее поддерживают).

С 2 grepс это становится:

make 2>&1 |
 {
   {
     tee /dev/fd/3 /dev/fd/4 |
       grep errors > errors.log 3>&- 4>&-
   } 4>&1 |
     grep warnings > warnings.log 3>&-
 } 3>&1

решение2

После того, как grep -E "errors|warnings" myfifo > errors.logканал больше не содержит данных, следующая команда cat myfifo, которая будет читать из канала, будет заблокирована.

Если я правильно понял ваш вопрос, вы хотите вывести все сообщения на stdout и перенаправить все сообщения об ошибках и предупреждения на errors.log. Так что если вы хотите использовать pipe, используйте два:

 mkfifo pipe1 pipe2 
 make 2>&1 | tee pipe1 pipe2 | grep -E "errors|warnings" pipe1 > errors.log | cat pipe2

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