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 testrequisito adicional de un cierre ]. Los integran [e testimitan la funcionalidad /bin/[y /bin/testjunto 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/shapunte. Así [[es la opción más moderna Bash / Zsh / Ksh.
Debido a que [[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:
No tiene que preocuparse por citar el lado izquierdo de la prueba para que realmente se lea como una variable.
No tiene que escapar menos y más que < >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/testse llama, lo que realmente no tendría sentido.
Gracias, el enlace a las preguntas frecuentes de bash era lo que estaba buscando (no sabía sobre esa página, gracias).
0x89
2
Edité su publicación con esta información, pero [y la prueba se ejecutan como incorporados. Los builtins fueron diseñados para reemplazar / bin / [y / bin / test pero también necesitaban reproducir las limitaciones de los binarios. El comando 'tipo [' verifica que se utiliza el incorporado. 'which [' solo busca ejecutables en la RUTA y es equivalente a 'type -P ['
klynch
133
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.
[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 testexcepto que testno busca un cierre ].
[ 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 Xse analice mágicamente. <, &&, ||Y ()se tratan de forma especial, y las reglas de división de palabras son diferentes.
[ 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 5
división de palabras y generación de nombre de archivo en expansiones (split + glob)
x='a b'; [[ $x = 'a b' ]]: cierto, no se necesitan citas
x='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:
perder portabilidad
obligar al lector a aprender las complejidades de otra extensión bash. [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 ao b(like +o index) y hace una comparación numérica si ay se bparecen a enteros decimales. expr "x$a" '<' "x$b"trabaja alrededor de ambos.
³ y también falla para algunos valores de ao blike !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.
@meeDamian 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.
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, lty 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
Basado en una lectura rápida de las secciones relevantes de la página de manual, la diferencia principal parece ser que los operadores ==y !=coinciden con un patrón, en lugar de una cadena literal, y también que existe el =~operador de comparación de expresiones regulares.
if
declaración, vea mywiki.wooledge.org/BashPitfalls#if_.5Bgrep_foo_myfile.5DRespuestas:
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 altest
requisito adicional de un cierre]
. Los integran[
etest
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 comandotype [
en Bash indica que[
se interpreta como un valor incorporado de forma predeterminada. (Nota:which [
solo busca ejecutables en la RUTA y es equivalente atype -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.fuente
En breve:
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:
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
fuente
[
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 detest
excepto quetest
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 queX
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? ]
: ela?
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
ob
(like+
oindex
) y hace una comparación numérica sia
y seb
parecen a enteros decimales.expr "x$a" '<' "x$b"
trabaja alrededor de ambos.³ y también falla para algunos valores de
a
ob
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.fuente
printf 'ab' | grep -Eq 'ab?'
dentroif [ … ]
?if ( printf 'ab' | grep -Eq 'a' ); then echo 'a'; fi
.[]
es un comando al igual quegrep
. 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 soloif 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
ygt
, 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:
fuente
Basado en una lectura rápida de las secciones relevantes de la página de manual, la diferencia principal parece ser que los operadores
==
y!=
coinciden con un patrón, en lugar de una cadena literal, y también que existe el=~
operador de comparación de expresiones regulares.fuente