Как вставить разрыв строки между stderr и stdout

Этот вопрос помог мне понять, как объединить 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))

Его цель состоит в том, чтобы удалить определенные строки из файлов журнала, оставив подходящие.

2
задан 21 August 2018 в 02:33

3 ответа

Вот один простой способ сделать это, принять эту команду:

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/
2
ответ дан 2 December 2019 в 01:53

Это возможно с дублированием дескрипторов файлов. Длинная история, короткая: передайте 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)

enter image description here


Обратиться к редактированию по вопросу, если необходимо отфильтровать и 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
2
ответ дан 2 December 2019 в 01:53

То, что действительно происходит, я думаю, - то, что 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
1
ответ дан 2 December 2019 в 01:53

Другие вопросы по тегам:

Похожие вопросы: