Pregunta ¿Cuál es la diferencia entre los corchetes dobles y simples en bash?


Me preguntaba cuál es exactamente la diferencia entre

[[ $STRING != foo ]]

y

[ $STRING != foo ]

Es decir, aparte de que este último es compatible con Posix, se encuentra en sh y el primero es una extensión que se encuentra en bash.


344
2017-08-09 21:11


origen


stackoverflow.com/questions/13542832 - Ciro Santilli 新疆改造中心 六四事件 法轮功
En caso de que también se esté preguntando acerca de no usar corchetes, por ejemplo. en el contexto de un if declaración, ver mywiki.wooledge.org/BashPitfalls#if_.5Bgrep_foo_myfile.5D - Kev
También, desde los documentos de Ubuntu: wiki.ubuntu.com/… - radistao


Respuestas:


Hay varias diferencias. En mi opinión, algunos de los más importantes son:

  1. [ es un builtin en Bash y muchas otras conchas modernas. El builtin [ es parecido a test Con el requisito adicional de un cierre. ]. Los builtins [ y test imitar 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. Ejecutando el comando type [ en Bash indica que [ Se interpreta como una incorporada por defecto. (Nota: which [ Solo busca ejecutables en el CAMINO y es equivalente a type -p [)
  2. [[ no es tan compatible, no necesariamente funcionará con lo que sea /bin/sh puntos a. Asi que [[ Es la opción más moderna de Bash / Zsh / Ksh.
  3. Porque [[ está integrado en el shell y no tiene requisitos heredados, no necesita preocuparse por la división de palabras basada en el IFS Variable para desordenar en variables que evalúan a una cadena con espacios. Por lo tanto, no es necesario poner la variable entre comillas dobles.

En su mayor parte, el resto es sólo 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 la prueba, [y [[?. De hecho, si usted es serio acerca de los scripts de bash, le recomiendo leer todo el wiki, incluyendo las preguntas frecuentes, Escollos, y 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 [[ es una mejor opción si no necesita preocuparse por ser tan portátil. Las principales razones son:

  1. No tiene que preocuparse por citar el lado izquierdo de la prueba para que realmente se lea como una variable.
  2. No tienes que escapar menos que y más grande que < > con barras invertidas para que no se evalúen como redirección de entrada, lo que realmente puede desordenar algunas cosas al sobrescribir archivos. Esto de nuevo se remonta a [[ siendo un builtin. Si [(test) es un programa externo, el shell tendría que hacer una excepción en la forma en que evalúa < y > sólo si /bin/test Está siendo llamado, lo que realmente no tendría sentido.

261
2017-08-09 21:56



Gracias, el enlace a las preguntas frecuentes de bash era lo que estaba buscando (no conocía esa página, gracias). - 0x89
Edité su publicación con esta información, pero [y la prueba se ejecutan como elementos incorporados. Las incorporaciones fueron diseñadas para reemplazar / bin / [y / bin / test pero también necesitaban reproducir las limitaciones de los binarios. El comando 'tipo [' verifica que se haya utilizado la función incorporada. 'que [' solo busca ejecutables en la RUTA y es equivalente a 'tipo -P [' - klynch


En breve:

[es una fiesta Incorporado

[[]] son ​​bash Palabras clave

Palabras clave: Las palabras clave son como integradas, pero la principal diferencia es que se aplican reglas de análisis especiales. Por ejemplo, [es un basin builtin, mientras que [[es una palabra clave bash. Ambos se usan para probar cosas, pero como [[es una palabra clave en lugar de una incorporada, se beneficia de unas pocas 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 realmente hace lo que esperas que haga. El carácter <ya no tiene su significado especial de operador de redirección de archivos.

Fuente: http://mywiki.wooledge.org/BashGuide/CommandsAndArguments


108
2017-12-29 19:42



[ es un comando de shell POSIX; no necesita ser construido en. ] es solo un argumento que busca ese comando, para que la sintaxis sea equilibrada. El comando es un sinónimo de test excepto eso test no busca un cierre ]. - Kaz
Mira aquí: pubs.opengroup.org/onlinepubs/009695399/utilities/test.html - Kaz


Diferencias de comportamiento

Probado en Bash 4.3.11:

  • POSIX vs extensión Bash:

    • [  es POSIX
    • [[ es una extensión de Bash
  • Comando regular vs magia

    • [ Es solo un comando regular con un nombre extraño.

      ] es solo un argumento de [ eso evita que se usen más argumentos.

      Ubuntu 16.04 en realidad tiene un ejecutable para él en /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 || concatenar comandos múltiples, ( ) genera subshells a menos que se escape por \, y la expansión de la palabra sucede como siempre.

    • [[ X ]] Es una sola construcción que hace. X ser analizado mágicamente. <, &&, || y () se tratan especialmente, 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

  • <

  • && y ||

    • [[ a = a && b = b ]]: verdadero, lógico y
    • [ a = a && b = b ]: error de sintaxis, && analizado como un separador de comando AND cmd1 && cmd2 
    • [ a = a -a b = b ]: equivalente, pero desaprobado por POSIX
    • [ a = a ] && [ b = b ]: Recomendación POSIX
  • (

    • [[ (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 () está en desuso por POSIX
    • ([ a = a ] || [ a = b ]) && [ a = b ] Recomendación POSIX
  • división de palabras

    • 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='a b'; [ "$x" = 'a b' ]: equivalente
  • =

    • [[ ab = a? ]]: cierto, porque lo hace la coincidencia de patrones (* ? [ son magias). No se expande a los archivos en el directorio actual.
    • [ ab = a? ]: a? glob se expande Por lo tanto, puede ser verdadero o falso según los archivos en el directorio actual.
    • [ ab = a\? ]: falso, no expansión global
    • = y == son iguales en ambos [ y [[, pero == Es una extensión de Bash.
    • printf 'ab' | grep -Eq 'a.': POSIX ERE equivalente
    • [[ ab =~ 'ab?' ]]: falso, pierde magia con ''
    • [[ ab? =~ 'ab?' ]]: cierto
  • =~

    • [[ ab =~ ab? ]]: verdadero, POSIX expresión regular extendida partido, ? no se expande glob
    • [ a =~ a ]: error de sintaxis
    • printf 'ab' | grep -Eq 'ab?': POSIX equivalente

Recomendación

Prefiero usar siempre [].

Hay equivalentes POSIX para cada [[ ]] Construí lo que he visto.

Si utiliza [[ ]] tú:

  • perder portabilidad
  • obligar al lector a aprender las complejidades de otra extensión de bash. [es solo un comando regular con un nombre extraño, no hay semántica especial involucrada.

61
2017-07-12 10:22



Cómo utilizar printf 'ab' | grep -Eq 'ab?' dentro if [ … ]? - meeDamian
@meeDamian if ( printf 'ab' | grep -Eq 'a' ); then echo 'a'; fi. [] es un comando al igual que grep. los () puede que no sea necesario en ese comando No estoy seguro: lo agregué debido a la |, depende de cómo Bash analiza las cosas. Si no hubiera | Estoy seguro de que puedes escribir solo if cmd arg arg; then. - Ciro Santilli 新疆改造中心 六四事件 法轮功
@meeDamian sí, no es necesario () parece: stackoverflow.com/questions/8965509/… - Ciro Santilli 新疆改造中心 六四事件 法轮功
Bonita lista Ver también: wiki.ubuntu.com/… - radistao


Sobre la base de una lectura rápida de las secciones relevantes de la página del manual, la diferencia principal parece ser que la == y != los operadores coinciden con un patrón, en lugar de una cadena literal, y también que existe la =~ operador de comparación de expresiones regulares.


4
2017-08-09 21:17





Solo soporte es decir [] Es POSIX shell compatible para encerrar una expresión condicional.

Soportes dobles es decir [[]] es una versión mejorada (o extensión) de la versión POSIX estándar, esto es compatible con bash y otros shells (zsh, ksh).

En bash, para comparación numérica utilizamos eq, ne,lt y gt, con dobles corchetes para comparación podemos utilizar ==, !=, <, y > literalmente.

  • [ es un sinónimo para 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

3
2018-02-08 03:15