Quiero probar un script simple
flag=false
while !$flag
do
read x
if [ "$x" -eq "true" ]
then
flag=true
fi
echo "${x} : ${flag}"
done
Pero cuando lo ejecuto, si escribo true
, lo veré x="true"
y flag="true"
, pero el ciclo no termina. ¿Qué tiene de malo el guión? ¿Cómo puedo invertir correctamente una variable booleana?
Respuestas:
Hay dos errores en su script. El primero es que necesita un espacio entre
!
y$flag
, de lo contrario, el shell busca un comando llamado!$flag
. El segundo error es que-eq
es para comparaciones de enteros, pero lo está utilizando en una cadena. Dependiendo de su shell, verá un mensaje de error y el ciclo continuará para siempre porque la condición[ "$x" -eq "true" ]
no puede ser verdadera, o cada valor no entero se tratará como 0 y el ciclo se cerrará si ingresa cualquier cadena (incluidafalse
) que no sea un número diferente de 0.Si bien
! $flag
es correcto, es una mala idea tratar una cadena como un comando. Funcionaría, pero sería muy sensible a los cambios en su secuencia de comandos, ya que necesitaría asegurarse de que$flag
nunca pueda ser otra cosa quetrue
ofalse
. Sería mejor usar una comparación de cadenas aquí, como en la prueba a continuación.Probablemente haya una mejor manera de expresar la lógica que busca. Por ejemplo, podría hacer un bucle infinito y romperlo cuando detecte la condición de terminación.
fuente
[
incorporado deksh
,[ x -eq y ]
devuelve verdadero si lax
expresión aritmética se resuelve en el mismo número que lay
expresión aritmética, por lo que, por ejemplo,x=2 true=1+1 ksh -c '[ x -eq true ] && echo yes'
generaría sí.Si bien no hay variables booleanas en Bash, es muy fácil emularlas mediante la evaluación aritmética.
Esto también funciona en ksh. No me sorprendería si funciona en todos los shells compatibles con POSIX, pero no he verificado el estándar.
fuente
! ! ((val))
Funciona en Bash, como en C o C ++? Por ejemplo, sival
es 0, sigue siendo 0 después! !
. Sival
es 1, queda 1 después! !
. Sival
es 8, se baja a 1 después! !
. ¿O necesito hacer otra pregunta?Si puede estar absolutamente seguro de que la variable contendrá 0 o 1, puede usar el operador XOR igual a bit para cambiar entre los dos valores:
fuente
Esto funciona para mi:
Pero, en realidad, lo que debe hacer es reemplazar su
while
con:fuente
No existe el concepto de una variable booleana en el shell.
Las variables de shell sólo podían ser
text
(una cadena), y, en algunos casos, que el texto puede ser interpretado como un entero (1
,0xa
,010
, etc.).Por lo tanto, a
flag=true
no implica veracidad o falsedad alguna para el caparazón.Cuerda
Lo que se podría hacer es una comparación de cadenas
[ "$flag" == "true" ]
o usar el contenido variable en algún comando y verificar sus consecuencias , como ejecutartrue
(porque hay un ejecutable llamadotrue
y uno llamadofalse
) como un comando y verificar si el código de salida de ese comando es cero (exitoso).O más corto:
Si el contenido de una variable se usa como un comando, a
!
podría usarse para negar el estado de salida del comando, si existe un espacio entre ambos (! cmd
), como en:El script debería cambiar a:
Entero
Use valores numéricos y expansiones aritméticas .
En este caso, el código de salida de
$((0))
is1
y el código de salida de$((1))
is0
.En bash, ksh y zsh, la aritmética podría llevarse a cabo dentro de a
((..))
(tenga en cuenta que$
falta el inicio ).flag=0; if ((flag)); then ... fi
Una versión portátil de este código es más complicada:
En bash / ksh / zsh puedes hacer:
Alternativamente
Puede "Invertir una variable booleana" (siempre que contenga un valor numérico) como:
((flag=!flag))
Eso va a cambiar el valor de
flag
que sea0
o1
.Nota : compruebe si hay errores en https://www.shellcheck.net/ antes de publicar su código como una pregunta, muchas veces es suficiente para encontrar el problema.
fuente
until
es la abreviatura dewhile !
(yuntil
, al contrario que!
Bourne), por lo que puede hacer:Que debería ser lo mismo que:
También puedes escribirlo como:
La parte entre
until
/while
ydo
no tiene que ser un solo comando.!
es una palabra clave en la sintaxis de shell POSIX. Debe estar delimitado, un token separado de lo que sigue y ser el primer token que precedió a una tubería (! foo | bar
niega la tubería yfoo | ! bar
no es válido, aunque algunos shells lo aceptan como una extensión).!true
se interpreta como el!true
comando que es poco probable que exista.! true
Deberia trabajar.!(true)
debería funcionar en shells compatibles con POSIX ya que!
está delimitado ya que está seguido por un(
token, pero en la práctica no funciona enksh
/bash -O extglob
donde entra en conflicto con el!(pattern)
operador de globo extendido ni zsh (excepto en la emulación sh) donde entra en conflictoglob(qualifiers)
conbareglobqual
yglob(group)
sin.fuente
o incluso:
debería hacer el trabajo
fuente