2012-10-05 15 views
7

Ho seguito alcune delle domande simili (come How to set a variable to the output from a command in Bash?), tuttavia le risposte accettate sembrano non funzionare per me. Non ero sicuro di dover far deragliare la domanda di qualcun altro o di pubblicare il mio duplicato, quindi scusami se ho scelto male qui.Come ottenere l'output di un comando bash in una variabile

Desidero ottenere lo stato di uscita e di uscita di un numero di comandi in uno script che sto mettendo insieme. Ecco un esempio di quello che ho usato:

cmd_output=$(rm $file) 
exit_status=$? 
if [ "${exit_status}" -eq 0 ] 
then 
log "Successfully removed the original" ${TAB_LEVEL} 
else 
fail "Failed to remove the original, the output was: \n ${cmd_output}" 
fi 

Il registro e non riescono funzioni sono:

# Usage: fail "Failure message" 
function fail { 
echo "FATAL ERROR: $1" >> "${LOG_DIR}/${LOG_FILE}" 
exit 1 
} 

# Usage: log "Log message" 3 Where the tab-level is 3. 
function log { 
if (("${2}" > 0)) 
then 
eval "printf ' %.0s' {1..$2}" >> "${LOG_DIR}/${LOG_FILE}" 
fi 
echo "$1" >> "${LOG_DIR}/${LOG_FILE}" 
return 0 
} 

Nel precedente esempio io uso il formato $ (cmd), ma ho anche provato usando i backtick.

Nel mio file di log, tutto quello che vedo quando c'è un fallimento è:

FATAL ERROR: Failed to remove the original, the output was: \n

Inoltre, l'output dei comandi falliti finisce sullo schermo come al solito. C'è una ragione comune per cui le mie variabili cmd_output sarebbero rimaste vuote?

risposta

22

È necessario includere l'output del flusso di output di errore standard speciale:

cmd_output=$(rm "$file" 2>&1) 

ci sono tre flussi di default su tutti i programmi (che sono numerati descrittori di file):

0. Standard input (where the program normally reads from) 
1. Standard output (where the program normally writes to) 
2. Standard error (where the program normally writes error messages) 

Quindi, per catturare i messaggi di errore, dobbiamo reindirizzare l'output di errore standard (stderr) nel normale output standard (stdout) che verrà quindi catturato dall'espressione $(...).

La sintassi per il reindirizzamento avviene tramite l'operatore ">". Immediatamente prima si indica quale reindirizzatore di file deve essere reindirizzato (il valore predefinito è 1, che è stdout). E puoi specificarlo per reindirizzare a un file. Se si scrive una e commerciale (&) dopo di essa, si forza a reindirizzare in un altro descrittore di file. Pertanto, in questo esempio, reindirizziamo il descrittore di file 2 (stderr) nel descrittore di file 1 (stdout).

Inoltre, è possibile reindirizzare l'input con < "operator", ma in questo caso il descrittore di file predefinito è 0 (stdin).

Un'altra osservazione è che è probabilmente una buona pratica posizionare la variabile $file tra virgolette doppie, nel caso in cui abbia spazi bianchi.

Spero che questo aiuti un po '=)

+1

Felice di spingerti oltre il marchio 1000, continua a postare! – shellter

+0

Hey Janito, grazie mille per la tua risposta! Sono a conoscenza dei tre flussi standard e degli operatori di reindirizzamento, ma l'unica ragione per cui li ho usati finora è quello di inviare qualsiasi cosa da un comando a/dev/null o ad un file di registro. Non ho nemmeno considerato i diversi flussi qui. La variabile $ file era in realtà originariamente tra virgolette, l'ho tolta dalle virgolette quando stavo testando le funzioni di cattura degli errori del mio script, per forzare un errore. Ancora una volta, grazie molte! –

5

* comando nix in genere hanno due forme di uscita: standard output (stdout) e l'errore standard (stderr).

FOO=$(...) acquisisce solo stdout e lascia senza impedimenti stderr.

Se si desidera che il contenuto di stderr con questa sintassi, è necessario a Postfix tuo comando con 2>&1 in modo che stderr viene unita stdout. (per esempio.in questo modo: rm $file 2>&1)

+0

Ciao antak, volevo solo dire grazie per la tua risposta. Come Janito è un po 'più dettagliato, lo sto lasciando come risposta accettata, ma apprezzo molto il tuo aiuto :). –

0

Dal momento che la funzione fail è solo uscendo, sarebbe molto più facile da fare semplicemente:

set -e # Abort on failure 
exec 2>> "${LOG_DIR}/${LOG_FILE}" # Append all errors to LOG_FILE 
if cmd_output=$(rm $file) 
    log "Successfully removed the original" ${TAB_LEVEL} 
fi 

L'unica differenza tra questo e il codice originale è che non è così stampa il testo FATAL ERROR:. Dal momento che la brevità è una virtù, probabilmente sarebbe meglio evitare la funzione log nella dimensione . Segnala errori ad alta voce; successo silenziosamente.

+0

Grazie William. In questo caso non voglio riuscire in silenzio, anche se dovessi scrivere un pacchetto per la distribuzione o per altri scopi, sarei d'accordo. Questo è in realtà un software in-house, e altrettanto importante quanto lo spostamento dei file è che mantiene dettagli molto chiari su ciò che è stato toccato (molto di ciò che viene spostato è dati sensibili o critici). Ho anche bisogno del prefisso FATAL ERROR: il file di log viene eseguito dalla macchina in cui i dati vengono copiati per cercare quello o qualche altro prefisso di riga. Grazie ancora! –

Problemi correlati