linux - script - ¿Cuál es el significado de a! antes de un comando en el shell?
shell script hello world (3)
La pregunta está en el título. ¿Cuál es el propósito de un comando de shell (parte de un script de shell) que comienza con un signo de exclamación? Ejemplo concreto:
En foo.sh:
#!/usr/bin/env bash
set -e
! docker stop foo
! docker rm -f foo
# ... other stuff
Sé que sin el espacio, el signo de exclamación se usa para reemplazar la historia y
! <expression>
! <expression>
acuerdo con la
página
del
manual
se puede utilizar para evaluar "
Verdadero si expr es falso
".
Pero en el contexto de ejemplo eso no tiene sentido para mí.
"!" Significa "no", así que cuando lo coloca antes de un comando y ejecuta "$?" Se hará eco de un 1. Lo que significa que falló en lugar de un 0, lo que significa éxito.
Si no desea que el script falle en ambos casos, error o éxito del comando, también puede usar esta alternativa:
set -e
docker stop foo || true
El valor booleano
o verdadero
hace que la canalización siempre tenga
0
como valor de retorno.
TL; DR: Esto es simplemente pasar por
set -e
indicador
set -e
en la línea específica donde lo está utilizando.
Agregar agregar a la respuesta correcta y útil de hek2mgl .
Tienes:
set -e
! command
Manual de referencia de Bash → Tuberías describe:
Cada comando en una tubería se ejecuta en su propia subshell. El estado de salida de una tubería es el estado de salida del último comando en la tubería (...). Si la palabra reservada ''!'' precede a la tubería, el estado de salida es la negación lógica del estado de salida como se describe anteriormente. El shell espera a que finalicen todos los comandos de la canalización antes de devolver un valor.
Esto significa que
!
preceder a un comando está negando el estado de salida del mismo:
$ echo 23
23
$ echo $?
0
# But
$ ! echo 23
23
$ echo $?
1
O:
$ echo 23 && echo "true" || echo "fail"
23
true
$ ! echo 23 && echo "true" || echo "fail"
23
fail
El estado de salida es útil de muchas maneras.
En su script, usado junto con
set -e
hace que el script salga cada vez que un comando devuelve un estado distinto de cero.
Por lo tanto, cuando tienes:
set -e
command1
command2
Si
command1
devuelve un estado distinto de cero, el script finalizará y no continuará con el
command2
.
Sin embargo, también hay un punto interesante para mencionar, descrito en 4.3.1 The Set Builtin :
-mi
Salga de inmediato si una tubería (vea Tuberías), que puede consistir en un solo comando simple (vea Comandos simples), una lista (vea Listas) o un comando compuesto (vea Comandos compuestos) devuelve un estado distinto de cero. El shell no sale si el comando que falla es parte de la lista de comandos inmediatamente después de un tiempo o hasta la palabra clave, parte de la prueba en una declaración if, parte de cualquier comando ejecutado en un && o || lista excepto el comando que sigue al && o || final, cualquier comando en una tubería pero el último, o si se invierte el estado de retorno del comando. . Si un comando compuesto que no sea un subshell devuelve un estado distinto de cero porque un comando falló mientras se ignoraba -e, el shell no se cierra. Una trampa en ERR, si se establece, se ejecuta antes de que salga el shell.
Tomando todo esto en consideración, cuando tiene:
set -e
! command1
command2
Lo que está haciendo es
set -e
indicador
set -e
en el
command1
.
¿Por qué?
-
si
command1
ejecuta correctamente, devolverá un estado cero.!
lo negará, peroset -e
no activará una salida por el porque proviene de un estado de retorno invertido con!, como se describió anteriormente. -
si
command1
falla, devolverá un estado distinto de cero.!
lo negará, por lo que la línea terminará devolviendo un estado cero y el script continuará normalmente.