tar to pipe, но держите -v подробный вывод отдельно от STDERR

12

Обычная команда tar

tar cvf foo.tar ./foo >foo.out 2>foo.err

имеет три выходных потока ввода-вывода

  • архивировать данные на foo.tar
  • список имен файлов для STDOUT (перенаправляется в foo.out)
  • сообщения об ошибках в STDERR (перенаправлены в foo.err)

Затем я могу проверить foo.err на наличие сообщений об ошибках, не просматривая список имен файлов.

если я хочу что-то сделать с архивными данными (передать через netcat или специальную программу сжатия), я могу использовать -f -опцию tar таким образом

tar cvf - ./foo 2>foo.err | squish > foo.tar.S

Но теперь мой список имен файлов смешан с моими сообщениями об ошибках, потому что -vвывод tar, очевидно, не может идти в STDOUT (туда, куда поступают архивные данные), поэтому tar ловко записывает это вместо этого в STDERR.

Используя оболочку Korn, есть способ создать команду, которая передает поток архива в другую команду, но при этом сохраняет -vвыходные данные отдельно от любых сообщений об ошибках.

RedGrittyBrick
источник
Вы знакомы с tee? Это похоже на вполне допустимый вариант использования.
HalosGhost

Ответы:

9

Если ваша система поддерживает /dev/fd/n:

tar cvf /dev/fd/3 ./foo 3>&1 > foo.out 2>foo.err | squish > foo.tar.S

Который с AT & T реализациями ksh(или bashили zsh) вы могли бы написать, используя подстановку процесса :

tar cvf >(squish > foo.tar.S) ./foo > foo.out 2>foo.err

Это происходит точно так же, за исключением того, что на этот раз оболочка решает, какой дескриптор файла использовать вместо 3(обычно выше 9). Другое отличие состоит в том, что на этот раз вы получаете статус выхода tarвместо squish. В системах, которые не поддерживают /dev/fd/n, некоторые оболочки могут использовать именованные каналы для этой функции.

Если ваша система не поддерживает /dev/fd/nили ваша оболочка не может использовать именованные каналы для подстановки процесса, то здесь вам придется иметь дело с именованными каналами вручную .

Стефан Шазелас
источник
6

Вы должны использовать именованный канал для этого.

Сначала создайте один в папке:

mkfifo foo.pipe

Затем используйте эту команду:

tar cvf foo.pipe ./foo >foo.out 2>foo.err & cat foo.pipe >foo.tar

Примечание:cat -часть, теперь может быть gzipили любой другой , который может читать из трубы:

tar cvf foo.pipe ./foo >foo.out 2>foo.err & gzip -c foo.pipe >foo.tar

Объяснение:

Вывод записывается на имя трубы ( foo.pipe), где другой proccess ( cat, gzip, netcat) считывает информацию с. Таким образом, вы не потеряете каналы stdout / stderr для получения информации.

хаос
источник
1
Возможно, стоит отметить последствия использования именованных каналов. 1) лучше всего установить umask 077(или использовать частный временный каталог) для предотвращения чтения или записи в него другими процессами (во многих системах именованные каналы, как и другие файлы, создаются по умолчанию для чтения всем миром), 2) вы должны убедиться, что именованный канал используется только каждым экземпляром вашего сценария (опять же, помогает одноразовый частный временный каталог). 3) Это означает, что вам нужно выполнить очистку впоследствии или в случае прерывания.
Стефан Шазелас
1
+1 - мне нравится этот ответ. К сожалению для меня, в именованных каналах моей (старой) системы есть странности, которые делают их ненадежными, когда я пытаюсь это сделать.
RedGrittyBrick
1
@ StéphaneChazelas - я думаю, что иногда бывает проще сначала убрать, например:p="/tmp/pipe$$"; mkfifo "$p"; (read na; cmd[s]...) <>"$p" & (echo;rm "$p"; cmd[s]...) >"$p"
mikeserv