¿Cómo verificar si un comando tuvo éxito?

235

¿Hay alguna forma de verificar si hay un error al ejecutar un comando?

Ejemplo:

test1=`sed -i "/:@/c connection.url=jdbc:oracle:thin:@$ip:1521:$dataBase" $search`
valid $test1

function valid () {
  if $test -eq 1; then
    echo "OK"
    else echo "ERROR" 
  fi
}

Ya intenté hacer eso, pero parece que no funciona. No sé cómo hacer eso.

moata_u
fuente
99
Prefiere $ (foo) sobre backticks `foo` , porque puede anidarlo y es más fácil distinguirlo de los apóstrofes.
usuario desconocido
1
Por cierto, debe definir una función ( valid) antes de llamarla.
wjandrea

Respuestas:

345

El valor de retorno se almacena en $?. 0 indica éxito, otros indica error.

some_command
if [ $? -eq 0 ]; then
    echo OK
else
    echo FAIL
fi

Al igual que cualquier otro valor textual, puede almacenarlo en una variable para futuras comparaciones:

some_command
retval=$?
do_something $retval
if [ $retval -ne 0 ]; then
    echo "Return code was not zero but $retval"
fi

Para posibles operadores de comparación, ver man test.

Lekensteyn
fuente
Eso está bien ... ¿puedo contener el error de salida? , porque en este caso tengo 2 errores: error de comando "texto" ex, archivo no encontrado y mi error "texto", que en este caso falló, por ejemplo
moata_u
@moata_u: puede almacenar el valor en una variable como se muestra en mi respuesta.
Lekensteyn
@moata_u: Necesita poner un ;antes de elsey fi: `if ...; luego ...; de lo contrario ...; fi
Lekensteyn
44
Este es un uso inútil detest .
David Foerster
1
@Blauhirn [ $? ](o equivalente test $?) no funciona porque se $?evalúa como un número (0, 1, etc.) que no es nulo. Consulte los documentos paratest : "Si se omite EXPRESIÓN, 'prueba' devuelve falso. Si EXPRESIÓN es un argumento único, 'prueba' devuelve falso si el argumento es nulo y verdadero de lo contrario".
Lekensteyn
87

Si solo necesita saber si el comando tuvo éxito o no, no se moleste en probarlo $?, solo pruebe el comando directamente. P.ej:

if some_command; then
    printf 'some_command succeeded\n'
else
    printf 'some_command failed\n'
fi

Y asignar la salida a una variable no cambia el valor de retorno (bueno, a menos que se comporte de manera diferente cuando stdout no es un terminal, por supuesto).

if output=$(some_command); then
    printf 'some_command succeded, the output was «%s»\n' "$output"
fi

http://mywiki.wooledge.org/BashGuide/TestsAndConditionals explica ifcon más detalle.

geirha
fuente
¿Qué sucede si desea hacer algo más que bifurcar, como almacenar el valor booleano de si falló o no en un .ini? Entonces su variable de salida no hace eso, pero lo $?hace, por lo que es incorrecto al decir que probar el comando directamente es estrictamente mejor.
Timothy Swan
Asignar la salida a una variable puede cambiar el valor de retorno cuando uno usa el localcomando, es decir, local foo=$(false); echo $?;produce 0en la salida. Pero localsolo es relevante dentro de las funciones bash.
Cromax
26
command && echo OK || echo Failed
Abraham Sanchez
fuente
Si commanddevuelve un error en la pantalla, ¿cómo ocultarlo?
Sigur
Si commandescribe errores en stderr, puede usar el formulario command 2> /dev/null && echo OK || echo Failed. Las 2> /dev/nullredirecciones Stderr de salida a /dev/null. Sin embargo, algunas utilidades escribirán errores en stdout (aunque esta sea una mala práctica). En este caso, puede omitir el 2 de la redirección, pero perderá cualquier resultado del comando. Este método de verificación del éxito es bueno para la lógica ternaria simple, pero para un comportamiento más complejo, es mejor verificar el $?éxito del comando o usar el ifmétodo de bloque descrito en la respuesta de @ geirha.
Bender the Greatest
17

PS debe contener el estado de salida del comando anterior, que debe ser cero para ningún error.

Entonces, algo así como;

cd /nonexistant
if [ $? -ne 0 ]
then
    echo failed
else
    echo success!
fi

Para la mayoría de los casos, es más fácil usar la construcción && para encadenar comandos que deben depender unos de otros. Por cd /nonexistant && echo success!lo tanto , no sería un éxito porque el comando se rompe antes de && El corolario de esto es ||, donde cd /nonexistant || echo fail se hacen eco fallar porque no cd. (Esto se vuelve útil si usa algo como || exit, que finalizará el script si falla el comando anterior).

Shaun
fuente
Eso está bien ... ¿puedo contener el error de salida? , porque en este caso tengo 2 errores: error de comando "texto" ex, archivo no encontrado y mi error "texto" que en este caso falló, por ejemplo
moata_u
@moata_u, vea mywiki.wooledge.org/BashFAQ/002
geirha
5
command && echo $? || echo $?
modrobert
fuente
Quieres decir command; echo $??
Javier Buzzi
No, mi línea es correcta, da el código de resultado real como un número, independientemente de si tuvo éxito o no.
modrobert
1
Ok, explícame las diferencias de estos: true && echo $? || echo $?/ true; echo $?y false && echo $? || echo $?/ false; echo $?- encontrarás que hacen exactamente lo mismo: D
Javier Buzzi el
Sí, el mismo resultado pero sin la condición. La pregunta original fue "¿Cómo verificar si un comando tuvo éxito?", Esto se basó en respuestas anteriores. Supongo que un mejor ejemplo sería:command && echo "success: $?" || echo "fail: $?"
modrobert
5

Cabe señalar que if...then...fiy &&/ ||tipo de enfoque trata con el estado de salida devuelto por comando que queremos probar (0 en caso de éxito); sin embargo, algunos comandos no devuelven un estado de salida distinto de cero si el comando falló o no pudo manejar la entrada. Esto significa que los enfoques habituales ify &&/ ||no funcionarán para esos comandos en particular.

Por ejemplo, en Linux, GNU filetodavía sale con 0 si recibió un archivo no existente como argumento y findno pudo ubicar el archivo especificado por el usuario.

$ find . -name "not_existing_file"                                          
$ echo $?
0
$ file ./not_existing_file                                                  
./not_existing_file: cannot open `./not_existing_file' (No such file or directory)
$ echo $?
0

En tales casos, una forma potencial de manejar la situación es mediante la lectura stderr/ stdinmensajes, por ejemplo, aquellos que regresaron por filecomando, o analizar la salida del comando como en find. Para ese propósito, se casepodría usar una declaración.

$ file ./doesntexist  | while IFS= read -r output; do                                                                                                                  
> case "$output" in 
> *"No such file or directory"*) printf "%s\n" "This will show up if failed";;
> *) printf "%s\n" "This will show up if succeeded" ;;
> esac
> done
This will show up if failed

$ find . -name "doesn'texist" | if ! read IFS= out; then echo "File not found"; fi                                                                                     
File not found

(Este es un reenvío de mi propia respuesta a una pregunta relacionada en unix.stackexchange.com )

Sergiy Kolodyazhnyy
fuente
1

Como se menciona en muchas otras respuestas, una simple prueba de $?lo hará, como esta

if [ $? -eq 0 ]; then something; fi

Si desea probar si el comando falló , puede usar una versión más corta bash(pero quizás exagerada) de la siguiente manera:

if (($?)); then something; fi

Esto funciona utilizando el (( ))modo aritmético, por lo que si el comando regresó success, es decir $? = 0, la prueba evalúa a ((0))qué pruebas false, de lo contrario, volverá true.

Para probar el éxito , puede usar:

if ! (($?)); then something; fi

pero ya no es mucho más corto que el primer ejemplo.

afuna
fuente
1
¿crítica constructiva?
afuna