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 hacer esto sin envolver todo el script dentro de un ciclo while y usar descansos? Algo así como un dun dun dun goto?
1
constantemente. Si el script está destinado a ser ejecutado por otro script, es posible que desee definir su propio conjunto de código de estado con un significado particular. Por ejemplo,1
== pruebas fallidas,2
== la compilación falló. Si el script es parte de otra cosa, es posible que deba ajustar los códigos para que coincidan con las prácticas utilizadas allí. Por ejemplo, cuando parte del conjunto de pruebas ejecutado por automake, el código77
se usa para marcar una prueba omitida.exit #
comando dentro de una función, no un script. (En cuyo caso, usereturn #
en su lugar.)exit 0
salga del script y devuelve 0 (indicando a otros scripts que podrían usar el resultado de este script que tuvo éxito)Use set -e
El script finalizará después de la primera línea que falla (devuelve un código de salida distinto de cero). En este caso, command-that-fail2 no se ejecutará.
Si tuviera que verificar el estado de retorno de cada comando, su script se vería así:
Con set -e se vería así:
Cualquier comando que falle hará que el script completo falle y devolverá un estado de salida que puede verificar con $? . Si su secuencia de comandos es muy larga o está creando muchas cosas, se volverá bastante feo si agrega comprobaciones de estado de devolución en todas partes.
fuente
set -e
Usted todavía puede hacer alguna salida de comandos con errores sin detener la secuencia de comandos:command 2>&1 || echo $?
.set -e
abortará el script si una tubería o estructura de comando devuelve un valor distinto de cero. Por ejemplofoo || bar
, fallará solo si ambosfoo
ybar
devuelven un valor distinto de cero. Por lo general, un script de bash bien escrito funcionará si agregaset -e
al principio y la adición funciona como un control de sanidad automatizado: cancele el script si algo sale mal.set -o pipefail
opción.set -e
sería justomake || exit $?
.set -u
. Echar un vistazo a la oficial modo estricto fiesta :set -euo pipefail
.Un tipo de SysOps una vez me enseñó la técnica de la Garra de tres dedos:
Estas funciones son * NIX OS y shell con buen sabor. Póngalos al comienzo de su script (bash o de otro modo),
try()
su declaración y código.Explicación
(basado en el comentario de ovejas voladoras ).
yell
: imprime el nombre del script y todos los argumentos enstderr
:$0
es el camino hacia el guión;$*
Son todos argumentos.>&2
significa>
redireccionar stdout a & pipe2
. La tubería1
sería enstdout
sí misma.die
hace lo mismo queyell
, pero sale con un estado de salida que no es 0 , lo que significa "falla".try
usa el||
(booleanoOR
), que solo evalúa el lado derecho si el izquierdo falló.$@
Es todo argumentos de nuevo, pero diferente .fuente
$0
es el camino hacia el guión.$*
Son todos argumentos.>&2
significa ">
redirigir stdout a la&
tubería2
". la tubería 1 sería stdout en sí misma. entonces grito antepone todos los argumentos con el nombre del script e imprime en stderr. morir hace lo mismo que gritar , pero sale con un estado de salida que no es 0, lo que significa "falla". try usa el booleano o||
, que solo evalúa el lado derecho si el izquierdo no falló.$@
Es todo argumentos de nuevo, pero diferente . Espero que eso lo explique tododie() { yell "$1"; exit $2; }
que pueda pasar un mensaje y salir del código condie "divide by zero" 115
.yell
ydie
. Sin embargo,try
no tanto. ¿Puedes dar un ejemplo de cómo lo usas?Si va a invocar la secuencia de comandos
source
, puede usarreturn <x>
dónde<x>
estará el estado de salida de la secuencia de comandos (use un valor distinto de cero para error o falso). Pero si invoca una secuencia de comandos ejecutable (es decir, directamente con su nombre de archivo), la declaración de devolución dará como resultado una queja (mensaje de error "return: solo puede" regresar "de una función o secuencia de comandos fuente).Si
exit <x>
se usa en su lugar, cuando se invoca el scriptsource
, dará como resultado la salida del shell que inició el script, pero un script ejecutable simplemente terminará, como se esperaba.Para manejar cualquier caso en el mismo script, puede usar
Esto manejará cualquier invocación que sea adecuada. Eso supone que utilizará esta declaración en el nivel superior del script. Aconsejaría que no salga directamente del script desde una función.
Nota:
<x>
se supone que es solo un número.fuente
A menudo incluyo una función llamada run () para manejar errores. Cada llamada que quiero hacer se pasa a esta función para que todo el script salga cuando se produce un error. La ventaja de esto sobre la solución set -e es que el script no sale 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.
fuente
set -e option
. A continuación, el comando, ya que es con argumentos, que utiliza comillas simples para evitar problemas de bash, así:runTry 'mysqldump $DB_PASS --user="$DB_USER" --host="$BV_DB_HOST" --triggers --routines --events --single-transaction --verbose $DB_SCHEMA $tables -r $BACKUP_DIR/$tables$BACKUP_FILE_NAME'
. Tenga en cuenta que he cambiado el nombre de la función para ejecutar Try.eval
es potencialmente peligroso si acepta entradas arbitrarias, pero de lo contrario, esto se ve bastante bien.En lugar de
if
construir, puede aprovechar la evaluación de cortocircuito :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.fuente
command -that --fails || exit $?
funciona sin paréntesis, ¿de qué se trataecho $[4/0]
que nos hace necesitarlos?echo $[4/0] || exit $?
) bash nunca ejecutará elecho
, y mucho menos obedecerá||
.Tengo la misma pregunta pero no puedo hacerla porque sería un duplicado.
La respuesta aceptada, usando exit, no funciona cuando el script es un poco más complicado. Si usa un proceso en segundo plano para verificar la condición, la salida 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 forma en que lo sé).
Aquí hay un pequeño script sobre cómo hacerlo:
Esta es una mejor respuesta pero aún incompleta, realmente no sé cómo deshacerme de la parte del boom .
fuente