Ich habe ein Programm, das Informationen in stdout
und schreibt stderr
, und ich muss grep
durchgehen, was zu stderr kommt , während ich stdout ignoriere .
Ich kann es natürlich in 2 Schritten tun:
command > /dev/null 2> temp.file
grep 'something' temp.file
aber ich würde es vorziehen, dies ohne temporäre Dateien tun zu können. Gibt es irgendwelche Tricks mit intelligenten Rohrleitungen?
command 2| othercommand
. Bash ist so perfekt, dass die Entwicklung 1982 endete, also werden wir das leider nie in Bash sehen.Antworten:
Leiten Sie zuerst stderr zu stdout um - das Rohr; leiten Sie dann stdout weiter
/dev/null
(ohne zu ändern, wohin stderr geht):Einzelheiten zur E / A-Umleitung in all ihren Varianten finden Sie im Kapitel zu Umleitungen im Bash-Referenzhandbuch.
Beachten Sie, dass die Reihenfolge der E / A-Umleitungen von links nach rechts interpretiert wird, aber Pipes eingerichtet werden, bevor die E / A-Umleitungen interpretiert werden. Dateideskriptoren wie 1 und 2 verweisen auf offene Dateibeschreibungen. Die Operation
2>&1
bewirkt, dass sich Dateideskriptor 2 alias stderr auf dieselbe geöffnete Dateibeschreibung bezieht, auf die sich Dateideskriptor 1 alias stdout derzeit bezieht (siehedup2()
undopen()
). Die Operation>/dev/null
ändert dann den Dateideskriptor 1 so, dass er auf eine offene Dateibeschreibung für verweist/dev/null
, aber das ändert nichts an der Tatsache, dass der Dateideskriptor 2 auf die offene Dateibeschreibung verweist, auf die der Dateideskriptor 1 ursprünglich zeigte - nämlich auf die Pipe.quelle
command 2> /dev/stdout 1> /dev/null | grep 'something'
/dev/stdout
et al. Oder verwenden/dev/fd/N
. Sie sind geringfügig weniger effizient, es sei denn, die Shell behandelt sie als Sonderfälle. Die reine numerische Notation beinhaltet nicht den Zugriff auf Dateien nach Namen, aber die Verwendung der Geräte bedeutet eine Suche nach Dateinamen. Ob Sie das messen können, ist umstritten. Ich mag die Prägnanz der numerischen Notation - aber ich benutze sie schon so lange (mehr als ein Vierteljahrhundert; autsch!), Dass ich nicht qualifiziert bin, ihre Vorzüge in der modernen Welt zu beurteilen.2>&1
, dh "verbinde stderr mit dem Dateideskriptor, zu dem stdout gerade geht". Die zweite Operation ist 'stdout so ändern, dass es zu/dev/null
' geht , wobei stderr zum ursprünglichen stdout, der Pipe, übergeht . Die Shell teilt zuerst die Elemente am Pipe-Symbol auf, sodass die Pipe-Umleitung vor der2>&1
oder>/dev/null
-Umleitung erfolgt, aber das ist alles. Die anderen Operationen sind von links nach rechts. (Von rechts nach links würde nicht funktionieren.)/dev/null
in das Windows-Äquivalentnul
).Oder verwenden Sie: Um die Ausgabe von Standardfehler und Standardausgabe zu vertauschen:
Dies erstellt einen neuen Dateideskriptor (3) und weist ihn derselben Stelle wie 1 (Standardausgabe) zu, weist dann fd 1 (Standardausgabe) derselben Stelle wie fd 2 (Standardfehler) zu und weist schließlich fd 2 (Standardfehler) zu ) an die gleiche Stelle wie fd 3 (Standardausgabe).
Der Standardfehler ist jetzt als Standardausgabe verfügbar und die alte Standardausgabe bleibt im Standardfehler erhalten. Dies mag übertrieben sein, gibt aber hoffentlich mehr Details zu Bash-Dateideskriptoren (für jeden Prozess stehen neun zur Verfügung).
quelle
3>&-
den Ersatzdeskriptor zu schließen, den Sie aus stdout erstellt habenstderr
und einen anderen, der die Kombination vonstderr
und hatstdout
? Mit anderen Worten, könnenstderr
zwei verschiedene Dateien gleichzeitig aufgerufen werden?In Bash können Sie mithilfe der Prozessersetzung auch zu einer Subshell umleiten :
Für den vorliegenden Fall:
quelle
command 2> >(grep 'something' > grep.log)
grep.log enthält die gleiche Ausgabe wie ungrepped.log voncommand 2> ungrepped.log
2> >(stderr pipe >&2)
. Andernfalls wird die Ausgabe der "stderr-Pipe" durch die "stdlog-Pipe" geleitet.2> >(...)
funktioniert, ich habe es versucht,2>&1 > >(...)
aber es hat nichtawk -f /new_lines.awk <in-content.txt > out-content.txt 2> >(tee new_lines.log 1>&2 )
In diesem Fall wollte ich auch sehen, was als Fehler auf meiner Konsole herauskam. Aber STDOUT ging zur Ausgabedatei. Innerhalb der Sub-Shell müssen Sie STDOUT also in den Klammern zurück zu STDERR umleiten. Währenddessen wird die STDOUT-Ausgabe destee
Befehls am Ende derout-content.txt
Datei beendet. Das scheint mir widersprüchlich.2>&1 1> >(dest pipe)
Kombinieren Sie die besten dieser Antworten, wenn Sie Folgendes tun:
command 2> >(grep -v something 1>&2)
... dann bleibt alles stdout als stdout und alles stderr als stderr erhalten, aber in stderr werden keine Zeilen mit der Zeichenfolge "etwas" angezeigt.
Dies hat den einzigartigen Vorteil, dass stdout und stderr nicht umgekehrt oder verworfen, nicht zusammengefügt oder temporäre Dateien verwendet werden.
quelle
command 2> >(grep -v something)
(ohne1>&2
) nicht dasselbe?tar cfz my.tar.gz mydirectory/ 2> >(grep -v 'changed as we read it' 1>&2)
funktionieren.Es ist viel einfacher, Dinge zu visualisieren, wenn Sie darüber nachdenken, was mit "Weiterleitungen" und "Pipes" wirklich los ist. Weiterleitungen und Pipes in bash bewirken eines: Ändern Sie, wohin die Prozessdateideskriptoren 0, 1 und 2 zeigen (siehe / proc / [pid] / fd / *).
Wenn ein Rohr oder "|" Der Operator ist in der Befehlszeile vorhanden. Als Erstes erstellt bash ein Fifo und zeigt die FD 1 des Befehls auf der linken Seite auf dieses Fifo und zeigt die FD 0 des Befehls auf der rechten Seite auf dasselbe Fifo.
Als nächstes werden die Umleitungsoperatoren für jede Seite von links nach rechts ausgewertet , und die aktuellen Einstellungen werden verwendet, wenn eine Duplizierung des Deskriptors auftritt. Dies ist wichtig, da FD1 (linke Seite) und FD0 (rechte Seite) seit dem ersten Einrichten der Pipe bereits von dem geändert wurden, was sie normalerweise gewesen sein könnten, und jede Verdoppelung dieser wird diese Tatsache widerspiegeln.
Wenn Sie also Folgendes eingeben:
Folgendes passiert in der Reihenfolge:
Alle Ausgaben, die "command" in seinen FD 2 (stderr) schreibt, gelangen in die Pipe und werden von "grep" auf der anderen Seite gelesen. Alle Ausgaben, die "Befehl" in seine FD 1 (stdout) schreibt, gelangen nach / dev / null.
Wenn Sie stattdessen Folgendes ausführen:
Folgendes passiert:
Also gehen alle stdout und stderr von "command" nach / dev / null. Es geht nichts in die Pipe, und daher wird "grep" geschlossen, ohne dass etwas auf dem Bildschirm angezeigt wird.
Beachten Sie auch, dass Weiterleitungen (Dateideskriptoren) schreibgeschützt (<), schreibgeschützt (>) oder schreibgeschützt (<>) sein können.
Eine letzte Anmerkung. Ob ein Programm etwas in FD1 oder FD2 schreibt, liegt ganz beim Programmierer. Die gute Programmierpraxis schreibt vor, dass Fehlermeldungen an FD 2 und die normale Ausgabe an FD 1 gesendet werden müssen. Sie werden jedoch häufig eine schlampige Programmierung finden, die beide vermischt oder die Konvention auf andere Weise ignoriert.
quelle
Wenn Sie Bash verwenden, verwenden Sie:
http://www.gnu.org/software/bash/manual/bashref.html#Pipelines
quelle
|&
ist gleich,2>&1
was stdout und stderr kombiniert. Die Frage wurde explizit für die Ausgabe ohne stdout gestellt.>/dev/null |&
erweitern Sie>/dev/null 2>&1 |
und bedeutet, dass stdout inode leer ist, um zu leiten, weil niemand (# 1 # 2 beide an / dev / null inode gebunden ist) an stdout inode gebunden ist (zBls -R /tmp/* >/dev/null 2>&1 | grep i
wird leer geben, aberls -R /tmp/* 2>&1 >/dev/null | grep i
lässt # 2, die an stdout inode gebunden ist, wird pfeifen).( echo out; echo err >&2 ) >/dev/null |& grep "."
gibt keine Ausgabe (wo wir "err" wollen).man bash
sagt, wenn | & verwendet wird ... ist eine Abkürzung für 2> & 1 |. Diese implizite Umleitung des Standardfehlers zur Standardausgabe erfolgt nach allen durch den Befehl angegebenen Umleitungen. Also leiten wir zuerst FD1 des Befehls auf null um, dann leiten wir FD2 des Befehls auf die Stelle um, auf die FD1 zeigte, d. H. null, also erhält greps FD0 keine Eingabe. Weitere Informationen finden Sie unter stackoverflow.com/a/18342079/69663 .Für diejenigen, die stdout und stderr dauerhaft in Dateien umleiten möchten, grep auf stderr, aber behalten Sie das stdout bei, um Nachrichten an ein tty zu schreiben:
quelle
Dadurch wird Befehl1 stderr zu Befehl2 stdin umgeleitet, während Befehl1 stdout unverändert bleibt.
Entnommen aus LDP
quelle
Ich habe gerade eine Lösung gefunden , um mithilfe von Named Pipes
stdout
an einen Befehl undstderr
an einen anderen zu senden .Hier geht.
Es ist wahrscheinlich eine gute Idee, die genannten Rohre anschließend zu entfernen.
quelle
Sie können die RC-Shell verwenden .
Installieren Sie zuerst das Paket (es ist weniger als 1 MB).
Dies ist ein Beispiel dafür , wie Sie die Standardausgabe und Rohrstandardfehler verwerfen würde grep in
rc
:Sie können es tun, ohne Bash zu verlassen:
Wie Sie vielleicht bemerkt haben, können Sie mithilfe von Klammern nach der Pipe angeben, welcher Dateideskriptor weitergeleitet werden soll.
Standard-Dateideskriptoren sind als solche nummeriert:
quelle
Ich versuche zu folgen, finde es auch funktionieren,
quelle