Me preguntaba cuál es exactamente la diferencia entre
[[ $STRING != foo ]]
y
[ $STRING != foo ]
es decir, además de que este último es compatible con posix, se encuentra en sh y el primero es una extensión que se encuentra en bash.
Me preguntaba cuál es exactamente la diferencia entre
[[ $STRING != foo ]]
y
[ $STRING != foo ]
es decir, además de que este último es compatible con posix, se encuentra en sh y el primero es una extensión que se encuentra en bash.
Respuestas:
Hay varias diferencias En mi opinión, algunos de los más importantes son:
[
es una construcción en Bash y muchos otros proyectiles modernos. La construcción [
es similar al test
requisito adicional de un cierre ]
. Los integran [
e test
imitan la funcionalidad /bin/[
y /bin/test
junto con sus limitaciones para que los scripts sean compatibles con versiones anteriores. Los ejecutables originales todavía existen principalmente para el cumplimiento de POSIX y la compatibilidad con versiones anteriores. Ejecutar el comando type [
en Bash indica que [
se interpreta como un valor incorporado de forma predeterminada. (Nota: which [
solo busca ejecutables en la RUTA y es equivalente a type -p [
)[[
no es tan compatible, no necesariamente funcionará con lo que sea que /bin/sh
apunte. Así [[
es la opción más moderna Bash / Zsh / Ksh.[[
está integrado en el shell y no tiene requisitos heredados, no necesita preocuparse por la división de palabras basada en la variable IFS para confundir las variables que se evalúan en una cadena con espacios. Por lo tanto, realmente no necesita poner la variable entre comillas dobles.En su mayor parte, el resto es solo una sintaxis más agradable. Para ver más diferencias, recomiendo este enlace a una respuesta de preguntas frecuentes: ¿Cuál es la diferencia entre prueba, [y [[? . De hecho, si te tomas en serio las secuencias de comandos bash, te recomiendo leer el wiki completo , incluidas las preguntas frecuentes, las trampas y la guía. La sección de prueba de la sección de guía también explica estas diferencias y por qué los autores piensan que [[
es una mejor opción si no necesita preocuparse por ser tan portátil. Las razones principales son:
< >
con barras invertidas para que no se evalúen como redireccionamiento de entrada, lo que realmente puede arruinar algunas cosas al sobrescribir los archivos. Esto vuelve a [[
ser una construcción. Si [(prueba) es un programa externo, el shell tendría que hacer una excepción en la forma en que se evalúa <
y >
solo si /bin/test
se llama, lo que realmente no tendría sentido.En breve:
[es un bash Builtin
[[]] son palabras clave bash
Palabras clave: las palabras clave son muy parecidas a las incorporadas, pero la principal diferencia es que se les aplican reglas de análisis especiales. Por ejemplo, [es un bash incorporado, mientras que [[es una palabra clave bash. Ambos se usan para probar cosas, pero dado que [[es una palabra clave en lugar de una función incorporada, se beneficia de algunas reglas de análisis especiales que lo hacen mucho más fácil:
$ [ a < b ]
-bash: b: No such file or directory
$ [[ a < b ]]
El primer ejemplo devuelve un error porque bash intenta redirigir el archivo b al comando [a]. El segundo ejemplo en realidad hace lo que esperas que haga. El carácter <ya no tiene su significado especial de operador Redirección de archivos.
Fuente: http://mywiki.wooledge.org/BashGuide/CommandsAndArguments
[
es un comando de shell POSIX; no necesita ser incorporado. ]
es solo un argumento que ese comando busca, para que la sintaxis esté equilibrada. El comando es sinónimo de test
excepto que test
no busca un cierre ]
.
Diferencias de comportamiento
Algunas diferencias en Bash 4.3.11:
Extensión POSIX vs Bash:
[
es POSIX[[
es una extensión Bash¹ documentada en: https://www.gnu.org/software/bash/manual/bash.html#Conditional-Constructscomando regular vs magia
[
es solo un comando regular con un nombre extraño.
]
es solo un argumento [
que evita que se utilicen más argumentos.
Ubuntu 16.04 en realidad tiene un ejecutable para él /usr/bin/[
proporcionado por coreutils, pero la versión integrada de bash tiene prioridad.
Nada se altera en la forma en que Bash analiza el comando.
En particular, <
es la redirección &&
y ||
concatena múltiples comandos, ( )
genera subcapas a menos que se escapen \
y la expansión de palabras ocurre como de costumbre.
[[ X ]]
es una construcción única que hace que X
se analice mágicamente. <
, &&
, ||
Y ()
se tratan de forma especial, y las reglas de división de palabras son diferentes.
También hay otras diferencias como =
y =~
.
En Bashese: [
es un comando incorporado y [[
es una palabra clave: https://askubuntu.com/questions/445749/whats-the-difference-between-shell-builtin-and-shell-keyword
<
[[ a < b ]]
: comparación lexicográfica[ a \< b ]
: Lo mismo que arriba. \
requerido o de lo contrario hace la redirección como para cualquier otro comando. Bash extension.expr a \< b > /dev/null
: POSIX equivalente², ver: https://stackoverflow.com/questions/21294867/how-to-test-strings-for-lexicographic-less-than-or-equal-in-bash/52707989#52707989&&
y ||
[[ a = a && b = b ]]
: verdadero, lógico y[ a = a && b = b ]
: error de sintaxis, &&
analizado como un separador de comando ANDcmd1 && cmd2
[ a = a -a b = b ]
: equivalente, pero obsoleto por POSIX³[ a = a ] && [ b = b ]
: POSIX y equivalente confiable(
[[ (a = a || a = b) && a = b ]]
: falso[ ( a = a ) ]
: error de sintaxis, ()
se interpreta como una subshell[ \( a = a -o a = b \) -a a = b ]
: equivalente, pero ()
es obsoleto por POSIX{ [ a = a ] || [ a = b ]; } && [ a = b ]
POSIX equivalente 5división de palabras y generación de nombre de archivo en expansiones (split + glob)
x='a b'; [[ $x = 'a b' ]]
: cierto, no se necesitan citasx='a b'; [ $x = 'a b' ]
: error de sintaxis, se expande a [ a b = 'a b' ]
x='*'; [ $x = 'a b' ]
: error de sintaxis si hay más de un archivo en el directorio actual.x='a b'; [ "$x" = 'a b' ]
: Equivalente POSIX=
[[ ab = a? ]]
: cierto, porque hace coincidir patrones ( * ? [
son mágicos). No se expande globalmente a los archivos en el directorio actual.[ ab = a? ]
: el a?
globo se expande. Por lo tanto, puede ser verdadero o falso dependiendo de los archivos en el directorio actual.[ ab = a\? ]
: falso, no expansión glob=
y ==
son iguales en ambos [
y [[
, pero ==
es una extensión Bash.case ab in (a?) echo match; esac
: Equivalente POSIX[[ ab =~ 'ab?' ]]
: falso 4 , pierde magia con''
[[ ab? =~ 'ab?' ]]
: cierto=~
[[ ab =~ ab? ]]
: verdadero, la coincidencia de expresión regular extendida POSIX , ?
no se expande globalmente[ a =~ a ]
: error de sintaxis. No hay bash equivalente.printf 'ab\n' | grep -Eq 'ab?'
: Equivalente POSIX (solo datos de una línea)awk 'BEGIN{exit !(ARGV[1] ~ ARGV[2])}' ab 'ab?'
: Equivalente POSIX.Recomendación : usar siempre []
.
Hay equivalentes POSIX para cada [[ ]]
construcción que he visto.
Si te [[ ]]
usas:
[
es solo un comando regular con un nombre extraño, no hay semántica especial involucrada.¹ Inspirado en la [[...]]
construcción equivalente en el shell Korn
² pero falla para algunos valores de a
o b
(like +
o index
) y hace una comparación numérica si a
y se b
parecen a enteros decimales. expr "x$a" '<' "x$b"
trabaja alrededor de ambos.
³ y también falla para algunos valores de a
o b
like !
or (
.
4 en bash 3.2 y superior y la compatibilidad proporcionada a bash 3.1 no está habilitada (como con BASH_COMPAT=3.1
)
5 aunque la agrupación (aquí con el {...;}
grupo de comandos en lugar del (...)
cual se ejecutaría una subshell innecesaria) no es necesaria ya que los operadores de shell ||
y &&
(en oposición a los operadores ||
y &&
[[...]]
o los operadores -o
/ -a
[
) tienen la misma prioridad. Entonces [ a = a ] || [ a = b ] && [ a = b ]
sería equivalente.
printf 'ab' | grep -Eq 'ab?'
dentro if [ … ]
?
if ( printf 'ab' | grep -Eq 'a' ); then echo 'a'; fi
. []
es un comando al igual que grep
. El ()
puede no ser necesario en ese comando no estoy seguro: he añadido debido a la |
, depende de cómo Bash analiza las cosas. Si no hubo |
, estoy seguro de que puedes escribir solo if cmd arg arg; then
.
()
parece necesario: stackoverflow.com/questions/8965509/…
Single Bracket,[]
es decir, es compatible con shell POSIX para encerrar una expresión condicional.
Double Brackets,[[]]
es decir, es una versión mejorada (o extensión) de la versión estándar POSIX, esto es compatible con bash y otros shells (zsh, ksh).
En bash, por comparación numérica usamos eq
, ne
, lt
y gt
, con soportes dobles para la comparación que podemos utilizar ==
, !=
, <,
y >
literalmente.
[
es sinónimo de comando de prueba. Incluso si está integrado en el shell, crea un nuevo proceso.[[
es una nueva versión mejorada de la misma, que es una palabra clave, no un programa. por ejemplo:
[ var1 lt var2] #works
[ var1 < var2] #error: var2 No such file or directory
[ var1 \< var2] #works with escape
[[ var1 < var2]] #works
if
declaración, vea mywiki.wooledge.org/BashPitfalls#if_.5Bgrep_foo_myfile.5D