Ist `xargs -t` Ausgabe stderr oder stdout und können Sie es kontrollieren?
-
20-08-2019 - |
Frage
sagen, ich habe ein Verzeichnis mit hi.txt und blah.txt und ich führen Sie den folgenden Befehl auf einer Linux-ish Befehlszeile
ls *.* | xargs -t -i{} echo {}
die Ausgabe sehen Sie, ist
echo blah.txt
blah.txt
echo hi.txt
hi.txt
Ich möchte die stderr-Ausgabe umleiten (sagen ‚echo blah.txt‘ nicht ...), nur die Ausgabe von dem xargs -t Befehl verlassen geschrieben std, aber es sieht aus, als ob es stderr als auch ist.
ls *.* | xargs -t -i{} echo {} 2> /dev/null
Gibt es eine Möglichkeit, es zu kontrollieren, um es Ausgabe an stdout?
Lösung
So glaube ich, was Sie wollen, ist zu haben, wie stdout
- die stdout aus dem Dienstprogramm, das xargs ausführt
- die Liste der Befehle, die von xargs erzeugt -t
Sie möchten den Stderr Strom durch die erzeugte ignorieren ausgeführt Dienstprogramm.
Bitte korrigieren Sie mich, wenn ich falsch bin.
Lassen Sie uns zunächst einen besseren Test-Utility erstellen:
% cat myecho
#!/bin/sh
echo STDOUT $@
echo STDERR $@ 1>&2
% chmod +x myecho
% ./myecho hello world
STDOUT hello world
STDERR hello world
% ./myecho hello world >/dev/null
STDERR hello world
% ./myecho hello world 2>/dev/null
STDOUT hello world
%
So, jetzt haben wir etwas, das tatsächlich sowohl stdout ausgibt und stderr, so dass wir Zwar können wir nur bekommen, was wir wollen.
Ein tangentialer Weg, dies zu tun, ist nicht xargs zu verwenden, sondern macht. In Anlehnung an einen Befehl und dann tut es ist irgendwie was machen tut. Das ist seine Tasche.
% cat Makefile
all: $(shell ls *.*)
$(shell ls): .FORCE
./myecho $@ 2>/dev/null
.FORCE:
% make
./myecho blah.txt 2>/dev/null
STDOUT blah.txt
./myecho hi.txt 2>/dev/null
STDOUT hi.txt
% make >/dev/null
%
Wenn Sie mit xargs gebunden sind, dann müssen Sie Ihre Nützlichkeit modifizieren, dass
xargs verwendet, so dass es Unterdrückt stderr. Dann können Sie die 2>&1
Trick andere verwenden
den Befehl bewegen Inserat von xargs erzeugt -t von stderr haben erwähnt,
auf die Standardausgabe.
% cat myecho2
#!/bin/sh
./myecho $@ 2>/dev/null
% chmod +x myecho2
% ./myecho2 hello world
STDOUT hello world
% ls *.* | xargs -t -i{} ./myecho2 {} 2>&1
./myecho blah.txt 2>/dev/null
STDOUT blah.txt
./myecho hi.txt 2>/dev/null
STDOUT hi.txt
% ls *.* | xargs -t -i{} ./myecho2 {} 2>&1 | tee >/dev/null
%
So funktioniert dieser Ansatz, und bricht zusammen alles, was Sie wollen stdout (Weglassen, was Sie nicht wollen).
Wenn Sie sich selbst finden dies zu tun viel, können Sie eine allgemeine Nützlichkeit schreiben stderr surpress:
% cat surpress_stderr
#!/bin/sh
$@ 2>/dev/null
% ./surpress_stderr ./myecho hello world
STDOUT hello world
% ls *.* | xargs -t -i{} ./surpress_stderr ./myecho {} 2>&1
./surpress_stderr ./myecho blah.txt 2>/dev/null
STDOUT blah.txt
./surpress_stderr ./myecho hi.txt 2>/dev/null
STDOUT hi.txt
%
Andere Tipps
Verwendung:
ls | xargs -t -i{} echo {} 2>&1 >/dev/null
Die 2>&1
sendet den Standardfehler von xargs
, wo die Standardausgabe wird derzeit gehen; die >/dev/null
sendet die ursprüngliche Standardausgabe /dev/null
. So ist das Nettoergebnis, dass die Standardausgabe enthält die Echo-Befehle und /dev/null
enthält die Dateinamen. Wir können über Leerzeichen in Dateinamen diskutieren und ob es einfacher wäre, einen sed
Skript zu verwenden zu setzen ‚Echo‘ an der Vorderseite jeder Zeile (ohne -t
Option), oder ob Sie könnten verwendet werden:
ls | xargs -i{} echo echo {}
(getestet. Solaris 10, Korn Shell, sollte auf anderen Schalen und Unix-Plattformen)
Wenn Sie nichts dagegen nicht das Innenleben der Befehle zu sehen, ich habe es geschafft, die Fehlerausgabe von xargs
und die Fehlerausgabe des Befehls ausgeführt zu trennen.
al * zzz | xargs -t 2>/tmp/xargs.stderr -i{} ksh -c "ls -dl {} 2>&1"
Der (Nicht-Standard) Befehl al
listet seine Argumente pro Zeile ein:
for arg in "$@"; do echo "$arg"; done
Die erste Umleitung (2>/tmp/xargs.stderr
) sendet die Fehlerausgabe von xargs
in die Datei /tmp/xargs.stderr
. Der Befehl ausgeführt ist ‚ksh -c "ls -dl {} 2>&1"
‘, die das Korn-Shell verwendet ls -ld
auf den Dateinamen mit jeder Fehlerausgabe geht auf der Standardausgabe auszuführen.
Der Ausgang in /tmp/xargs.stderr
wie folgt aussieht:
ksh -c ls -dl x1 2>&1
ksh -c ls -dl x2 2>&1
ksh -c ls -dl xxx 2>&1
ksh -c ls -dl zzz 2>&1
verwendet I 'ls -ld
' anstelle von echo
, um sicherzustellen, ich teste Fehler -. Die Dateien x1
, x2
und xxx
existierte, aber zzz
nicht
Die Ausgabe auf der Standardausgabe sah aus wie:
-rw-r--r-- 1 jleffler rd 1020 May 9 13:05 x1
-rw-r--r-- 1 jleffler rd 1069 May 9 13:07 x2
-rw-r--r-- 1 jleffler rd 87 May 9 20:42 xxx
zzz: No such file or directory
Wenn ohne den Befehl eingewickelt in ‚ksh -c "..."
‘ laufen, die I / O-Umleitung wurde als Argument für den Befehl ( ‚ls -ld
‘) geführt und berichtet daher, dass es nicht die Datei ‚2>&1
‘ gefunden. Das heißt, xargs
hat sich nicht die Shell verwenden, um die E / A-Umleitung zu tun.
Es wäre möglich, für verschiedene andere Umleitungen zu arrangieren, aber das grundlegende Problem ist, dass xargs
seinen eigenen Fehlerausgang keine Bestimmung macht aus, dass die Befehle zur Trennung führt sie, so ist es schwer zu tun.
Die andere ziemlich offensichtliche Option ist xargs
zu verwenden, um ein Shell-Skript zu schreiben, und haben dann die Shell ausführen. Dies ist die Option, die ich zeigte vor:
ls | xargs -i{} echo echo {} >/tmp/new.script
Sie können dann sehen Sie die Befehle mit:
cat /tmp/new.script
Sie können die Befehle ausführen, um die Fehler mit verwerfen:
sh /tmp/new.script 2>/dev/null
Und wenn Sie nicht wollen, entweder, hängen 1>&2
an das Ende des Befehls die Standardausgabe von den Befehlen sehen.
xargs -t
echos die Befehle vor der Ausführung sie in stderr ausgeführt werden. Wenn Sie sie wollen stderr statt echo können Sie Rohr stderr mit dem 2>&1
Konstrukt nach stdout:
ls *.* | xargs -t -i{} echo {} 2>&1
Es sieht aus wie xargs -t nach stderr geht, und es gibt nicht viel können Sie dagegen tun können.
Sie können tun:
ls | xargs -t -i{} echo "Foo: {}" >stderr.txt | tee stderr.txt
nur die stderr Daten auf dem Endgerät als Befehl ausgeführt wird, um anzuzeigen, und dann durch stderr.txt grep nach, um zu sehen, ob etwas unerwartet aufgetreten ist, entlang der Linien von grep -v Foo: stderr.txt
Beachten Sie auch, dass auf Unix, ls *.*
ist nicht, wie Sie alles, was angezeigt werden soll. Wenn Sie alle Dateien sehen wollen, nur läuft ls
auf seinem eigenen.
Wie ich verstehe Ihr Problem mit GNU Parallel http://www.gnu.org/software/ parallel / würde das richtige tun:
ls *.* | parallel -v echo {} 2> /dev/null