Nascondere l'output di un comando shell solo in caso di successo?


12

Nascondere l'output di un comando shell di solito comporta il reindirizzamento di stderr e stdout. C'è qualche funzione o comando integrato che nasconde di default l'output ma in caso di errore scarica tutto l'output accumulato? Vorrei eseguire questo come wrapper per i sshcomandi remoti . Ora li ho usando il reindirizzamento, ma non ho idea di cosa li abbia fatti fallire, e sono troppo prolissi.

EDIT: Alla fine ho creato il seguente modello basato sulla risposta di @Belmin che ho modificato un po 'per accumulare tutti i comandi precedenti dallo script, utilizzare l'identificatore del processo corrente, rimuovere automaticamente il registro e aggiungere un errore rosso di errore messaggio quando qualcosa va storto. In questo modello i silentwrapper iniziali avranno esito positivo, quindi falliranno il terzo comando perché la directory esiste già:

#!/bin/sh

set -e

SILENT_LOG=/tmp/silent_log_$$.txt
trap "/bin/rm -f $SILENT_LOG" EXIT

function report_and_exit {
    cat "${SILENT_LOG}";
    echo "\033[91mError running command.\033[39m"
    exit 1;
}

function silent {
    $* 2>>"${SILENT_LOG}" >> "${SILENT_LOG}" || report_and_exit;
}

silent mkdir -v pepe
silent mkdir -v pepe2
silent mkdir -v pepe
silent mkdir -v pepe2

2
Se reindirizzi solo stdout, stderr verrà comunque visualizzato; è sufficiente per te o vuoi vedere anche stdout se c'è un errore?
Kromey,

Voglio vedere entrambi, ma solo se qualcosa va storto, altrimenti non voglio vedere nulla.
Grzegorz Adam Hankiewicz,

2
Quello che faccio è stampare stdout e stderr su un file di registro in modo che non ingombra lo schermo. Ho anche stampare stderr allo schermo, quindi se ci sono e l'errore posso vederlo. Se ho bisogno di dettagli, posso controllare il file di registro, che contiene l'output del programma e gli errori del programma nel contesto. In questo modo, posso "vedere entrambi ma solo se qualcosa va storto". questo aiuta? Vedere stackoverflow.com/questions/2871233/...
Stefan Lasiewski

1
È sicuro reindirizzare stderr e stdout sullo stesso file con due reindirizzamenti separati? Ho pensato che dovremmo sempre usare 2>&1qualcosa del genere:$* >>"${SILENT_LOG}" 2>&1" || report_and_exit
psmith,

Risposte:


3

Configurerei una funzione bash come questa:

function suppress { /bin/rm --force /tmp/suppress.out 2> /dev/null; ${1+"$@"} > /tmp/suppress.out 2>&1 || cat /tmp/suppress.out; /bin/rm /tmp/suppress.out; }

Quindi, potresti semplicemente eseguire il comando:

suppress foo -a bar

Un utente malintenzionato che ha accesso non root al proprio sistema, potrebbe tentare di creare un collegamento simbolico tra rm e la chiamata di comando, che indichi /etc/passswdo qualche altro file critico e sovrascriva il contenuto.
Mitar,

1
A proposito, l'ordine dei reindirizzamenti sopra dovrebbe essere: $* > /tmp/surpress.out 2>&1Questo cattura davvero lo standard.
Mitar,

2
$*non è il migliore per gestire input arbitrari. Soprattutto quando contiene spazi o bandiere. La maggior parte portatile è ${1+"$@"}in base alla stackoverflow.com/questions/743454/...
balrok

Modificato per entrambi i commenti. Grazie --- buone informazioni.
Belmin Fernandez,


7

Dovrebbe essere abbastanza facile scrivere una sceneggiatura per questo scopo.

Qualcosa di simile a questo script completamente non testato.

OUTPUT=`tempfile`
program_we_want_to_capture &2>1 > $OUTPUT
[ $? -ne 0 ]; then
    cat $OUTPUT
    exit 1
fi
rm $OUTPUT

D'altra parte per i comandi che eseguo come parte di uno script di solito voglio qualcosa di meglio che semplicemente stampare tutto l'output. Spesso limito ciò che vedo all'ignoto. Ecco una sceneggiatura che mi sono adattata da qualcosa che ho letto più di dieci anni fa.

#!/bin/bash

the_command 2>&1 | awk '
BEGIN \
{
  # Initialize our error-detection flag.
  ErrorDetected = 0
}
# Following are regex that will simply skip all lines
# which are good and we never want to see
/ Added UserList source/ || \
/ Added User/ || \
/ init domainlist / || \
/ init iplist / || \
/ init urllist / || \
/ loading dbfile / || \
/^$/ {next} # Uninteresting message.  Skip it.

# Following are lines that we good and we always want to see
/ INFO: ready for requests / \
{
  print "  " $0 # Expected message we want to see.
  next
}

# any remaining lines are unexpected, and probably error messages.  These will be printed out and highlighted.
{
  print "->" $0 # Unexpected message.  Print it
  ErrorDetected=1
}

END \
{
  if (ErrorDetected == 1) {
    print "Unexpected messages (\"->\") detected in execution."
    exit 2
  }
}
'
exit $?

5

Non penso che ci sia un modo pulito per farlo, l'unica cosa che mi viene in mente è

  • Cattura l'output del comando.
  • Controllare il valore restituito dal comando e se ha esito negativo
    • visualizza l'output acquisito.

L'implementazione di questo potrebbe essere un progetto interessante ma forse al di là delle domande e risposte.


Dovrebbe essere fattibile con una funzione. Lasciami provare.
Belmin Fernandez,

1

andare a corto di qualcosa del genere tehcommand &>/tmp/$$ || cat /tmp/$$

dipende da quanto usabilità / digitazione desideri / necessiti. (es. usandolo come pipe o passando il comando per argomento)

Lo script breve di @zoredache è sostanzialmente un proto-wrapper per questo, che darebbe più robustezza, gestirà la concorrenza, ecc.


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.