Bash ignorando l'errore per un particolare comando


445

Sto usando le seguenti opzioni

set -o pipefail
set -e

In bash script per interrompere l'esecuzione in caso di errore. Ho ~ 100 righe di esecuzione dello script e non voglio controllare il codice di ritorno di ogni riga dello script.

Ma per un comando particolare, voglio ignorare l'errore. Come lo posso fare?

Risposte:


757

La soluzione:

particular_script || true

Esempio:

$ cat /tmp/1.sh
particular_script()
{
    false
}

set -e

echo one
particular_script || true
echo two
particular_script
echo three

$ bash /tmp/1.sh
one
two

three non verrà mai stampato.

Inoltre, voglio aggiungere che quando pipefailè attivo, è sufficiente che la shell pensi che l'intero pipe abbia un codice di uscita diverso da zero quando uno dei comandi nel pipe ha un codice di uscita diverso da zero (con pipefailoff deve essere l'ultimo) .

$ set -o pipefail
$ false | true ; echo $?
1
$ set +o pipefail
$ false | true ; echo $?
0

15
+1. Come spiega il Manuale di riferimento di Bash , "La shell non si chiude" quando -eviene impostato l' attributo "se il comando che fallisce fa parte dell'elenco dei comandi immediatamente dopo una whileo untilparola chiave, parte del test in ifun'istruzione, parte di qualsiasi comando eseguito in un elenco &&o ||tranne il comando che segue il comando finale &&o ||, qualsiasi comando in una pipeline tranne l'ultimo, o se lo stato di ritorno del comando viene invertito con !. "
Ruakh,

@IgorChubin Non so perché, ma questo non funziona output = lo (ldd $2/bin/* || true) | grep "not found" | wc -lscript termina dopo questa riga quando ldd restituisce un errore
Vivek Goel,

1
(ldd $2/bin/* || true) | grep "not found" | wc -l || true
Igor Chubin,

1
a causa di set -o pipefail. quando grepnon trova nulla, restituisce un codice di uscita diverso da zero ed è sufficiente che la shell pensi che l'intero tubo abbia un codice di uscita diverso da zero.
Igor Chubin,

3
Se desideri l'opzione di preservare il valore restituito (senza uscire), prova a provare mycommand && true. Ciò consente di controllare il codice di ritorno nei passaggi successivi e gestirlo a livello di codice.
Ed Ost,

179

Basta aggiungere || truedopo il comando in cui si desidera ignorare l'errore.


11
Penso che sia importante aggiungere questo: questo metodo permetterà al codice di risposta e al messaggio di errore di persistere, mentre il "!" il metodo descritto di seguito modificherà il codice di risposta e quindi non genererà l'errore. Questo è importante quando si utilizza set -ee si tenta di acquisire un messaggio di errore: ad es.set -e; TEST=$(foo 2>&1 || true); echo $TEST
Spanky,

88

Non fermarti e salva anche lo stato di uscita

Nel caso in cui si desideri che lo script non si interrompa se un determinato comando non riesce e si desidera salvare anche il codice di errore del comando non riuscito:

set -e
EXIT_CODE=0
command || EXIT_CODE=$?
echo $EXIT_CODE

2
Questo è esattamente ciò di cui avevo bisogno
sarink,

non funziona per me per qualche motivo ... vabbè
Jeef il

EXIT_CODE non è impostato su zero quando il comando restituisce 0. Tuttavia, vengono acquisiti codici di uscita diversi da zero. Qualche idea sul perché?
Ankita13,

@ Ankita13 Perché se era zero il primo ha commandavuto successo e c'è bisogno di eseguire ciò che è dopo ||. leggilo come: se commandfallisce, fallo EXIT_CODE=$?. Probabilmente potresti semplicemente fare command || echo "$?"o usare "trap" per un debug più dettagliato. Vedere questo -> stackoverflow.com/a/6110446/10737630
tinnick

63

Più conciso:

! particular_script

Dalle specifiche POSIX riguardanti set -e(il mio accento):

Quando questa opzione è attiva, se un semplice comando non riesce per uno dei motivi elencati in Conseguenze degli errori della shell o restituisce un valore dello stato di uscita> 0 e non fa parte dell'elenco composto dopo un po ', fino a quando o se la parola chiave e non fa parte di un elenco AND o OR e non è una pipeline preceduta da! parola riservata , quindi la shell uscirà immediatamente.


16
Questo inverte semplicemente il codice di uscita di un comando, quindi il comando completato correttamente restituirà 1 invece di 0 e fallirà lo script con -e.
Marboni,

17
La mia comprensione è che la !volontà impedirà alla shell di uscire, qualunque cosa accada. Questo script visualizza il messaggio Still alive!quando lo eseguo, indicando che lo script è stato completato. Vedi comportamenti diversi?
Lily Finley,

7
hai ragione, inverte lo stato di uscita, ma non blocca lo script quando il comando termina con 0 o 1. Ero distratto. Comunque, grazie per aver citato la documentazione, ho messo la mia espressione in ifclausola e ho risolto il problema.
Marboni,

42

Invece di "restituire true", puoi anche usare "noop" o l'utilità null (come indicato nelle specifiche POSIX ) :e semplicemente "non fare nulla". Salverai qualche lettera. :)

#!/usr/bin/env bash
set -e
man nonexistentghing || :
echo "It's ok.."

3
sebbene ||: non sia così chiaro come || vero (che può confondere gli utenti non esperti), mi piace la concisione
David

Questa variante non restituisce alcun testo che può essere importante in CI.
kivagant

5

Se si desidera impedire il fallimento dello script e raccogliere il codice di ritorno:

command () {
    return 1  # or 0 for success
}

set -e

command && returncode=$? || returncode=$?
echo $returncode

returncode viene raccolto indipendentemente dal fatto che il comando abbia esito positivo o negativo.


2

Ho usato lo snippet di seguito quando lavoro con gli strumenti della CLI e voglio sapere se esiste qualche risorsa o meno, ma non mi interessa l'output.

if [ -z "$(cat no_exist 2>&1 >/dev/null)" ]; then
    echo "none exist actually exist!"
fi

1
Questo sembra essere un modo veramente rotatorio e moderatamente costoso da direif [ -r not_exist ]
tripleee

1

Mi piace questa soluzione:

: `particular_script`

Il comando / script tra i segni di spunta posteriori viene eseguito e il suo output viene inviato al comando ":" (che è l'equivalente di "true")

$ false
$ echo $?
1
$ : `false`
$ echo $?
0

modifica: corretto errore di battitura


0

mentre || trueè preferito uno, ma puoi anche farlo

var=$(echo $(exit 1)) # it shouldn't fail

0

Nessuna soluzione ha funzionato per me da qui, quindi ne ho trovata un'altra:

set +e
find "./csharp/Platform.$REPOSITORY_NAME/obj" -type f -iname "*.cs" -delete
find "./csharp/Platform.$REPOSITORY_NAME.Tests/obj" -type f -iname "*.cs" -delete
set -e

Questo è utile per CI e CD. In questo modo vengono stampati i messaggi di errore ma l'intero script continua a essere eseguito.


0
output=$(*command* 2>&1) && exit_status=$? || exit_status=$?
echo $output
echo $exit_status

Esempio di utilizzo di questo per creare un file di registro

log_event(){
timestamp=$(date '+%D %T') #mm/dd/yy HH:MM:SS
echo -e "($timestamp) $event" >> "$log_file"
}

output=$(*command* 2>&1) && exit_status=$? || exit_status=$?

if [ "$exit_status" = 0 ]
    then
        event="$output"
        log_event
    else
        event="ERROR $output"
        log_event
fi

0

Grazie per la semplice soluzione qui sopra:

<particular_script/command> || true

La seguente costruzione potrebbe essere utilizzata per ulteriori azioni / risoluzione dei problemi di istruzioni di script e opzioni di controllo del flusso aggiuntive:

if <particular_script/command>
then
   echo "<particular_script/command> is fine!"
else
   echo "<particular_script/command> failed!"
   #exit 1
fi

Siamo in grado di frenare le ulteriori azioni e, exit 1se necessario.

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.