
Я пытаюсь распределить очень длинный вывод 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 идут в P1tee myfifo
: stdin из P1, stdout в P2. Поэтомуtee
записывает вывод и в P2myfifo
, и в P2.grep -E "errors|warnings" myfifo > errors.log
: stdin из P2, но вы передаете имя файла (myfifo
)grep
, поэтомуgrep
не будет считывать его со stdin. stdout идет вerrors.log
, ничего не пишется в P3cat 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
Если вам нужно больше grep
s, вам нужно больше 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