Этот вопрос помог мне понять, как объединить stderr и stdout:
Как перенаправить stderr в файл
с этой командой:
gunzip -vc /opt/minecraft/wonders/logs/20* 2>&1
Но как можно вставить разрыв строки между двумя так, чтобы вывод мог появиться на отдельных строках вместо собранного в группу вместе?
stderr на первом месте, который всегда является 1 строкой, чем-то вроде этого:
/opt/minecraft/wonders/logs/2017-08-28-2.log.gz:
Принимая во внимание, что stdout обычно является (но не всегда) несколькими строками, как:
06:17:05: Starting minecraft server version 1.10.2
06:18:21: Loading properties
06:18:21: Default game type: SURVIVAL
06:18:21: Generating keypair
06:18:21: Starting Minecraft server on *:25565
06:18:22: Using default channel type
Но потому что нет никакой новой строки между ними, первая строка из каждого файла, который будет разархивирован, всегда является чем-то вроде этого:
/opt/minecraft/wonders/logs/2018-08-18-2.log.gz: 06:17:05: Starting minecraft server version 1.10.2
Мне нужны эти две части на различных строках, таким образом, я могу отфильтровать их с grep. Но я также хочу соответствующий stdout непосредственно после его stderr (его имя файла), таким образом, я знаю, из какого файла он прибывает. Как это:
/opt/minecraft/wonders/logs/2018-08-18-2.log.gz:
06:17:05: Starting minecraft server version 1.10.2
06:18:21: Loading properties
06:18:21: Default game type: SURVIVAL
06:18:21: Generating keypair
06:18:21: Starting Minecraft server on *:25565
06:18:22: Using default channel type
Это - команда, которую я передаю по каналу в использование с grep:
egrep -iv "^\[.*(stopping|starting|saving|keep|spawn|joined|lost|left|: (<.*>|\/)|\/(help|forge))
Его цель состоит в том, чтобы удалить определенные строки из файлов журнала, оставив подходящие.
Вот один простой способ сделать это, принять эту команду:
ls -d Documents/ NotExist/ /dev/null
вывод:
ls: cannot access 'NotExist/': No such file or directory
/dev/null Documents/
первая строка stderr
и второе stdout
, если я передаю вывод по каналу к xargs
Я могу распечатать новую строку после stderr
и затем печать stdout
:
ls -d Documents/ NotExist/ /dev/null | xargs echo -e '\n'
который дает мне:
ls: cannot access 'NotExist/': No such file or directory
/dev/null Documents/
Это возможно с дублированием дескрипторов файлов. Длинная история, короткая: передайте stderr по каналу, где он может быть обработан, и отправлять stdin на терминал управления (стенография для этого /dev/tty
) так, чтобы это все еще показало на экране:
$ stat /etc/passwd noexist 2>&1 > /dev/tty | while IFS= read -r line; do echo "---"; echo "$line"; echo "---"; done
File: /etc/passwd
Size: 2380 Blocks: 8 IO Block: 4096 regular file
Device: 801h/2049d Inode: 937653 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2018-08-20 13:05:01.171247259 +0800
Modify: 2018-07-24 04:51:36.799057737 +0800
Change: 2018-07-24 04:51:36.867020035 +0800
Birth: -
---
stat: cannot stat 'noexist': No such file or directory
---
Здесь я разделяю stderr с ---
строка, но Вы получаете идею.
Иначе, если Вы хотите визуально разделить их, к colorize вывод. На основе ответа Balazs Pozar Вы могли сделать:
command 2> >(while read line; do echo -e "\e[01;31m$line\e[0m" >&2; done)
Обратиться к редактированию по вопросу, если необходимо отфильтровать и stdout и stderr с grep
(например, если Вы ищете шаблон в stdout
, но другой шаблон в stderr
), Вы используете несколько замен процесса >()
:
gunzip -vc /opt/minecraft/wonders/logs/20* > >(grep 'stdin pattern' ) 2> >(grep 'stderrpattern' )
Обращение к комментариям, если только необходимо разделить имя файла /opt/minecraft/wonders/logs/2017-08-28-2.log.gz:
от дальнейшего содержания Вы могли использовать sed
:
gunzip -vc /opt/minecraft/wonders/logs/20* |
sed -r 's/^(\/opt\/minecraft\/wonders\/logs\/2018-08-18-2.log.gz:) *(.*)$/\1\n\2/'
Тест:
$ echo /opt/minecraft/wonders/logs/2018-08-18-2.log.gz: 06:17:05: Starting minecraft server version 1.10.2 | sed -r 's/^(\/opt\/minecraft\/wonders\/logs\/2018-08-18-2.log.gz:) *(.*)$/\1\n\2/'
/opt/minecraft/wonders/logs/2018-08-18-2.log.gz:
06:17:05: Starting minecraft server version 1.10.2
То, что действительно происходит, я думаю, - то, что stdout становится смешанным в stderr, потому что первый с буфером строки, и последний освободил буфер по умолчанию. Проиллюстрировать:
$ gunzip -vc ../foo.txt.gz
../foo.txt.gz: some text here
more text here
26.7%
(отметьте это -v
заставляет два сведения испускаться на stderr: имя файла и сжатие % - со стандартным выводом, падающим промежуточный).
Если Вы буфер строки stderr также, потоки появятся на отдельных строках:
$ stdbuf -eL gunzip -vc ../foo.txt.gz
some text here
more text here
../foo.txt.gz: 26.7%
однако не обязательно в порядке, которого Вы требуете - Вы могли бы попытаться использовать sponge
утилита для впитывания всех stdout перед выводом это, так, чтобы вывод stderr (имя файла и %) появился в терминале сначала:
gunzip -vc ../foo.txt.gz | sponge
../foo.txt.gz: 26.7%
some text here
more text here