tar to pipe, aber halten Sie -v ausführliche Ausgabe von STDERR getrennt

12

Ein normaler Tar-Befehl

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

hat drei Ausgangs-E / A-Streams

  • Daten in foo.tar archivieren
  • Liste der Dateinamen zu STDOUT (umgeleitet in foo.out)
  • Fehlermeldungen an STDERR (umgeleitet in foo.err)

Ich kann dann foo.err auf Fehlermeldungen untersuchen, ohne die Liste der Dateinamen durchlesen zu müssen.

Wenn ich etwas mit den Archivdaten machen möchte (durch Netcat oder ein spezielles Komprimierungsprogramm leiten), kann ich die -f -Option von tar verwenden

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

Aber jetzt ist meine Liste der Dateinamen mit meinen Fehlermeldungen gemischt, da die -vAusgabe von tar offensichtlich nicht an STDOUT gehen kann (dort fließen die Archivdaten), so dass tar dies geschickt in STDERR schreibt.

Mit der Korn-Shell können Sie einen Befehl erstellen, der den Archivdatenstrom an einen anderen Befehl weiterleitet und die -vAusgabe dennoch getrennt von Fehlermeldungen erfasst .

RedGrittyBrick
quelle
Kennen Sie sich aus tee? Dies scheint ein ziemlich gültiger Anwendungsfall dafür zu sein.
HalosGhost

Antworten:

9

Wenn Ihr System unterstützt /dev/fd/n:

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

Was Sie mit AT & T-Implementierungen von ksh(oder bashoder zsh) mithilfe von Prozesssubstitution schreiben könnten :

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

Das ist genau das Gleiche, außer dass diesmal die Shell entscheidet, welcher Dateideskriptor anstelle von 3(normalerweise über 9) verwendet werden soll. Ein weiterer Unterschied besteht darin, dass Sie diesmal den Exit-Status von taranstelle von erhalten squish. Auf Systemen, die dies nicht unterstützen /dev/fd/n, greifen einige Shells möglicherweise auf Named Pipes für diese Funktion zurück.

Wenn Ihr System dies nicht unterstützt /dev/fd/noder Ihre Shell Named Pipes nicht für die Prozessersetzung verwenden kann, müssen Sie Named Pipes von Hand bearbeiten .

Stéphane Chazelas
quelle
6

Dafür müssen Sie eine Named Pipe verwenden.

Erstellen Sie zuerst eine im Ordner:

mkfifo foo.pipe

Verwenden Sie dann diesen Befehl:

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

Hinweis: Der cat-part kann jetzt auch sein gzipoder was auch immer, der aus einer Pipe lesen kann:

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

Erläuterung:

Der Ausgang ist mit dem Namen Rohr (geschrieben foo.pipe), wo eine andere Proccess ( cat, gzip, netcat) liest aus. Sie verlieren also nicht die stdout / stderr-Kanäle, um Informationen zu erhalten.

Chaos
quelle
1
Könnte erwähnenswert sein, welche Auswirkungen die Verwendung eines benannten Rohrs hat. 1) Am besten legen Sie ein umask 077(oder verwenden Sie ein privates temporäres Verzeichnis) fest, um zu verhindern, dass andere Prozesse darauf lesen oder schreiben (auf vielen Systemen werden Named Pipes wie andere Dateien standardmäßig weltweit lesbar erstellt). 2) Sie müssen dies sicherstellen Die Named Pipe wird nur von jeder Instanz Ihres Skripts verwendet (wieder hilft ein einmaliges privates temporäres Verzeichnis). 3) Das bedeutet, dass Sie danach oder bei Unterbrechung bereinigen müssen.
Stéphane Chazelas
1
+1 - Ich mag diese Antwort. Leider gibt es auf meinem (alten) System eine gewisse Verrücktheit in Named Pipes, die sie unzuverlässig macht, wenn ich dies versuche.
RedGrittyBrick
1
@ StéphaneChazelas - Ich denke, es kann manchmal einfacher sein, zuerst aufzuräumen, wie:p="/tmp/pipe$$"; mkfifo "$p"; (read na; cmd[s]...) <>"$p" & (echo;rm "$p"; cmd[s]...) >"$p"
MikeServ
5

Die --index-fileOption von GNU tar funktioniert gut:

tar cvf - ./foo 2>foo.err --index-file=foo.out | squish > foo.tar.S
Josh Kelley
quelle