bash - programas - shell script linux español
En un script de Bash, ¿cómo puedo salir del script completo si se produce una determinada condición? (7)
A menudo incluyo una función llamada run () para manejar los errores. Todas las llamadas que quiero hacer se pasan a esta función, por lo que la secuencia de comandos completa se cierra cuando se produce un error. La ventaja de esto sobre la solución set -e es que la secuencia de comandos no se cierra silenciosamente cuando falla una línea, y puede decirle cuál es el problema. En el siguiente ejemplo, la tercera línea no se ejecuta porque la secuencia de comandos sale en la llamada a falso.
function run() {
cmd_output=$(eval $1)
return_value=$?
if [ $return_value != 0 ]; then
echo "Command $1 failed"
exit -1
else
echo "output: $cmd_output"
echo "Command succeeded."
fi
return $return_value
}
run "date"
run "false"
run "date"
Estoy escribiendo un script en Bash para probar un código. Sin embargo, parece una tontería ejecutar las pruebas si la compilación del código falla en primer lugar, en cuyo caso simplemente abortaré las pruebas.
¿Hay alguna manera de que pueda hacer esto sin ajustar todo el script dentro de un bucle while y usando cortes? ¿Algo así como un dun dun dun goto?
En lugar de construir, puede aprovechar la evaluación de cortocircuito :
#!/usr/bin/env bash
echo $[1+1]
echo $[2/0] # division by 0 but execution of script proceeds
echo $[3+1]
(echo $[4/0]) || exit $? # script halted with code 1 returned from `echo`
echo $[5+1]
Tenga en cuenta el par de paréntesis que es necesario debido a la prioridad del operador de alternancia. $?
es una variable especial establecida para salir del código del comando llamado más recientemente.
Prueba esta afirmación:
exit 1
Reemplace 1
con códigos de error apropiados. Consulte también Códigos de salida con significados especiales .
Si invoca el script con source
, puede usar return <x>
donde <x>
será el estado de salida del script (use un valor distinto de cero para error o false). Esto también funcionará como se esperaba, cuando source
la secuencia de comandos, pero si invoca una secuencia de comandos ejecutable (es decir, directamente con su nombre de archivo), la declaración de retorno dará lugar a una queja (mensaje de error "return: solo se puede ''devolver'' desde un Función o script de origen ").
Si se usa exit <x>
su lugar, cuando el script se invoca con source
, resultará en salir del shell que inició el script, pero un script ejecutable se ejecutará directamente bien.
Para manejar cualquiera de los casos en el mismo script, puede usar
return <x> 2> /dev/null || exit <x>
Esto manejará cualquier invocación que sea adecuada.
Nota: <x>
se supone que es solo un número.
Tengo la misma pregunta pero no puedo hacerla porque sería un duplicado.
La respuesta aceptada, utilizando exit, no funciona cuando el script es un poco más complicado. Si usa un proceso en segundo plano para verificar la condición, exit solo sale de ese proceso, ya que se ejecuta en un sub-shell. Para matar el script, debes matarlo explícitamente (al menos esa es la única manera que conozco).
Aquí hay un pequeño guión sobre cómo hacerlo:
#!/bin/bash
boom() {
while true; do sleep 1.2; echo boom; done
}
f() {
echo Hello
N=0
while
((N++ <10))
do
sleep 1
echo $N
# ((N > 5)) && exit 4 # does not work
((N > 5)) && { kill -9 $$; exit 5; } # works
done
}
boom &
f &
while true; do sleep 0.5; echo beep; done
Esta es una respuesta mejor, pero aún incompleta. Realmente no sé cómo deshacerme de la parte de auge .
Un chico malo de SysOps una vez me enseñó la técnica de la garra de tres dedos:
yell() { echo "$0: $*" >&2; }
die() { yell "$*"; exit 111; }
try() { "$@" || die "cannot $*"; }
Estas funciones son * NIX OS y shell con sabor robusto. Póngalos al comienzo de su script (bash o de otra manera), try()
su declaración y su código.
Explicación
(basado en el comentario de ).
-
yell
: imprime el nombre del script y todos los argumentos astderr
:-
$0
es la ruta al script; -
$*
son todos los argumentos. -
>&2
significa>
redireccionar stdout a & pipe2
. la pipa1
seríastdout
sí.
-
-
die
hace lo mismo queyell
, pero sale con un estado de salida distinto a 0 , que significa "falla". -
try
usar el||
(booleanoOR
), que solo evalúa el lado derecho si el izquierdo no falló.-
$@
es todos los argumentos otra vez, pero different .
-
Espero que lo explique todo.
Utilice set -e
#!/bin/bash
set -e
/bin/command-that-fails
/bin/command-that-fails2
La secuencia de comandos terminará después de la primera línea que falla (devuelve un código de salida distinto de cero). En este caso, el comando-that-fail2 no se ejecutará.
Si tuviera que verificar el estado de retorno de cada comando único, su script se vería así:
#!/bin/bash
# I''m assuming you''re using make
cd /project-dir
make
if [[ $? -ne 0 ]] ; then
exit 1
fi
cd /project-dir2
make
if [[ $? -ne 0 ]] ; then
exit 1
fi
Con set -e se vería como:
#!/bin/bash
set -e
cd /project-dir
make
cd /project-dir2
make
Cualquier comando que falle causará que todo el script falle y devolverá un estado de salida que puede verificar con $? . Si tu script es muy largo o estás creando muchas cosas, se pondrá muy feo si agregas controles de estado de retorno en todas partes.