Перенаправление вывода в зависимости от grep regex

8

Я использую gradle runдля запуска сервера REST. Вывод сервера REST выглядит следующим образом:

XXX.XXX.XX.XXX - <moreinfo>
randomtext
randomtext
XXX.XXX.XX.XXX - <moreinfo>
XXX.XXX.XX.XXX - <moreinfo>
randomtext
XXX.XXX.XX.XXX - <moreinfo>

XXX.XXX.XX.XXXздесь IP-адрес, случайный текст сообщения об ошибках. К сожалению, весь вывод направлен на стандартный вывод.

Как я могу направить все строки, начиная с IP-адреса, в файл, который называется, err.logи в любую другую строку all.log?

К сожалению, gradle runможет быть запущен только один раз и не останавливается, поскольку это REST-сервер.

Может использовать tee, grepсочетание?

Polym
источник

Ответы:

8

В Bash вы можете использовать процесс подстановки с помощью tee:

tee >(grep XXX > err.log) | grep -v XXX > all.log

Это поместит все строки, соответствующие XXX err.log, и все строки в all.log. >( ... )создает процесс в скобках и подключает его стандартный вывод к каналу. Это работает в zsh и других современных оболочках тоже.

Вы также можете использовать peeкоманду из moreutils :

pee "grep XXX > err.log" "grep -v XXX > all.log"

pee перенаправляет стандартный ввод на несколько команд («тройник для труб»).

Еще одна альтернатива с awk:

awk '{ if (/^([0-9]{1,3}\.){3}[0-9]{1,3}/) { print > "err.log" } else { print > "all.log" } }'

Это просто проверяет каждую строку на соответствие выражению и записывает все, err.logесли оно совпадает, а all.logесли нет.

Регулярное выражение awk также подходит для этого grep -E(хотя оно соответствует некоторым неправильным адресам - 999.0.0.0и так далее, - но это, вероятно, не проблема).

Майкл Гомер
источник
Хм err.logпусто, и весь вывод перенаправлен на all.logиспользование teeкоманды выше.
полим
Убедитесь, что ваше регулярное выражение действительно соответствует правильным строкам - если вообще err.logсуществует, то команда выполнялась, но ничего не вышло. grep -Eс выражением, используемым в команде awk, должно совпадать или здесь.
Майкл Гомер
Ах, хорошо, я понял. Можете ли вы изменить свой вопрос так, чтобы all.logв выражении grep не было совпавших строк?
полим
Готово - я не был уверен, какой вы хотели, поэтому у меня были оба.
Майкл Гомер
О, черт возьми, это сработало. Я переписал all.logи err.logсо старой командой. Извините за путаницу. Спасибо, ты классный :)) !!
полим
4

Так, похоже , gradle runне соответствует tee, pee, grepи Ио-перенаправление. Он всегда перестает читать после 4096 байт.

Чтобы обойти эту проблему, я в readкаждой строке gradle run. Я еще не тестировал, но думаю, что чтение строки длиной более 4 тыс. Символов также не удастся.

Во всяком случае, вот код для решения моего вопроса конкретно:

#!/bin/bash
STDOUTLOG="/log/stdout.txt"
STDERRLOG="/log/stderr.txt"
while read -r line; do
    [[ $line =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}.* ]] && printf '%s\n' "$line" >> "$STDERRLOG" && continue
    printf '%s\n' "$line" >> "$STDOUTLOG"
done < <(gradle run)
Polym
источник
1
Вы должны использовать read -r lineи printf '%s\n' "$line"избегать некоторых крайних случаев, ломающих вещи.
nyuszika7h
@ nyuszika7h Спасибо! Я изменил ответ соответственно :).
Полим