Domanda

dire che ho una directory con hi.txt e blah.txt ed eseguo il seguente comando su una riga di comando linux-ish

ls *.* | xargs -t -i{} echo {}

l'output che vedrai è

echo blah.txt
blah.txt
echo hi.txt
hi.txt

Vorrei reindirizzare l'output di stderr (dire 'echo blah.txt' non riesce ...), lasciando solo l'output del comando xargs -t scritto su std out, ma esso sembra che sia anche stderr.

ls *.* | xargs -t -i{} echo {} 2> /dev/null

C'è un modo per controllarlo, per renderlo output su stdout?

È stato utile?

Soluzione

Quindi credo che quello che vuoi sia avere come stdout

  • lo stdout dall'utilità che xargs esegue
  • l'elenco dei comandi generati da xargs -t

Si desidera ignorare il flusso stderr generato da utilità eseguita.

Per favore, correggimi se sbaglio.

Innanzitutto, creiamo una migliore utility di test:

% 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
%

Quindi ora abbiamo qualcosa che in realtà emette sia su stdout che su stderr, quindi noi puoi essere sicuro che stiamo ottenendo solo ciò che vogliamo.

Un modo tangenziale per farlo non è usare xargs, ma piuttosto, make. Facendo eco a un comando e poi farlo è una specie di cosa fa fare. Questa è la sua borsa.

% 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
% 

Se sei legato all'utilizzo di xargs, allora devi modificarlo xargs usa così sorprende stderr. Quindi puoi usare il 2>&1 trucco degli altri hanno menzionato di spostare l'elenco dei comandi generato da xargs -t da stderr su stdout.

% 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
%

Quindi questo approccio funziona e fa crollare tutto ciò che vuoi stdout (tralasciando ciò che non vuoi).

Se ti ritrovi a fare molto, puoi scrivere un'utilità generale per sorprendere stderr:

% 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
%

Altri suggerimenti

Usa:

ls | xargs -t -i{} echo {} 2>&1 >/dev/null

2>&1 invia l'errore standard da xargs a dove sta andando l'output standard; >/dev/null invia l'output standard originale a /dev/null. Pertanto, il risultato netto è che l'output standard contiene i comandi echo e sed contiene i nomi dei file. Possiamo discutere degli spazi nei nomi dei file e se sarebbe più facile usare uno script -t per mettere 'echo' all'inizio di ogni riga (senza l'opzione al), o se potresti usare:

ls | xargs -i{} echo echo {}

(Testato: Solaris 10, Korn Shell; dovrebbe funzionare su altre shell e piattaforme Unix.)


Se non ti dispiace vedere il funzionamento interno dei comandi, sono riuscito a separare l'output dell'errore da 2>/tmp/xargs.stderr e l'output dell'errore del comando eseguito.

al * zzz | xargs -t 2>/tmp/xargs.stderr -i{} ksh -c "ls -dl {} 2>&1"

Il comando (non standard) /tmp/xargs.stderr elenca i suoi argomenti uno per riga:

for arg in "$@"; do echo "$arg"; done

Il primo reindirizzamento (ksh -c "ls -dl {} 2>&1") invia l'output dell'errore da ls -ld al file echo. Il comando eseguito è 'x1', che utilizza la shell Korn per eseguire x2 sul nome del file con qualsiasi output di errore che passa all'output standard.

L'output in xxx è simile a:

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

Ho usato 'zzz' al posto di ksh -c "..." per assicurarmi di verificare gli errori: i file 1>&2, <=> e <=> esistevano, ma <=> no.

L'output sull'output standard era simile:

-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

Quando eseguito senza il comando racchiuso in '<=>', il reindirizzamento I / O è stato passato come argomento al comando ('<=>') e ha quindi segnalato che non è stato possibile trovare il file '< =>'. Ossia, <=> non ha utilizzato la shell per eseguire il reindirizzamento I / O.

Sarebbe possibile organizzare vari altri reindirizzamenti, ma il problema di base è che <=> non prevede la separazione del proprio output di errori da quello dei comandi che esegue, quindi è difficile farlo.

L'altra opzione piuttosto ovvia è usare <=> per scrivere uno script di shell, e quindi eseguirlo dalla shell. Questa è l'opzione che ho mostrato prima:

ls | xargs -i{} echo echo {} >/tmp/new.script

Puoi quindi vedere i comandi con:

cat /tmp/new.script

È possibile eseguire i comandi per eliminare gli errori con:

sh /tmp/new.script 2>/dev/null

E, se non vuoi vedere neanche l'output standard dai comandi, aggiungi <=> alla fine del comando.

xargs -t echo i comandi da eseguire su stderr prima di eseguirli. Se vuoi invece che facciano eco a stderr, puoi reindirizzare stderr a stdout con il costrutto 2>&1:

ls *.* | xargs -t -i{} echo {} 2>&1

Sembra che xargs -t vada a stderr e non c'è molto che tu possa fare al riguardo.

Potresti fare:

ls | xargs -t -i{} echo "Foo: {}" >stderr.txt | tee stderr.txt

per visualizzare solo i dati stderr sul tuo terminale mentre il tuo comando è in esecuzione, e poi passare attraverso stderr.txt per vedere se si è verificato qualcosa di imprevisto, lungo le linee di grep -v Foo: stderr.txt

Nota anche che su Unix, ls *.* non è come visualizzi tutto. Se vuoi vedere tutti i file, esegui ls da solo.

Come ho capito il tuo problema usando GNU Parallel http://www.gnu.org/software/ parallel / farebbe la cosa giusta:

ls *.* | parallel -v echo {} 2> /dev/null
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top