Diferencia entre corchetes simples y dobles en Bash

Estoy leyendo bash ejemplos sobre if pero algunos ejemplos están escritos con corchetes individuales:

 if [ -f $param ] then #... fi 

otros con doble corchetes cuadrados:

 if [[ $? -ne 0 ]] then start looking for errors in yourlog fi 

¿Cuál es la diferencia?

Single [] son pruebas de condición que cumplen con el shell posix.

Double [[]] son una extensión del estándar [] y son compatibles con bash y otras shells (por ejemplo, zsh, ksh). Admiten operaciones adicionales (así como las operaciones posix estándar). Por ejemplo: || en lugar de -o y regex matching con =~ . Se puede encontrar una lista más completa de diferencias en la sección manual de bash sobre construcciones condicionales .

Utilice [] cada vez que desee que su script sea portable a través de shells. Utilice [[]] si desea expresiones condicionales no admitidas por [] y no es necesario que sean portátiles.

Diferencias de comportamiento

Probado en Bash 4.3.11:

  • Extensión POSIX vs Bash:

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

    • [ es solo un comando regular con un nombre raro.

      ] es solo un argumento de [ que evita que se usen argumentos adicionales.

      Ubuntu 16.04 realmente tiene un ejecutable en /usr/bin/[ provisto por coreutils, pero la versión bash incorporada tiene prioridad.

      Nada se altera en la forma en que Bash analiza el comando.

      En particular, < es la redirección, && y || concatenar múltiples comandos, ( ) genera subcapas a menos que escapen con \ , 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 () son tratados 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%5D

  • <

    • [[ a < b ]] : comparación lexicográfica
    • [ a \< b ] : lo mismo que arriba. \ required o de lo contrario redirecciona como para cualquier otro comando. Bash extensión.
    • No pude encontrar una alternativa POSIX a esto, vea: ¿Cómo probar cadenas para menor o igual?
  • && y ||

    • [[ a = a && b = b ]] : verdadero, lógico y
    • [ a = a && b = b ] : error de syntax, && analizado como un separador de comandos AND cmd1 && cmd2
    • [ a = a -ab = b ] : equivalente, pero obsoleto por POSIX
    • [ a = a ] && [ b = b ] : recomendación de POSIX
  • (

    • [[ (a = a || a = b) && a = b ]] : falso
    • [ ( a = a ) ] : error de syntax, () se interpreta como una subcapa
    • [ \( a = a -oa = b \) -aa = 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 = 'ab' ]] x='a b'; [[ $x = 'ab' ]] : verdadero, no se necesitan citas
    • x='a b'; [ $x = 'ab' ] x='a b'; [ $x = 'ab' ] : error de syntax, se expande a [ ab = 'ab' ]
    • x='a b'; [ "$x" = 'ab' ] x='a b'; [ "$x" = 'ab' ] : equivalente
  • =

    • [[ ab = a? ]] [[ ab = a? ]] : verdadero, porque coincide con el patrón ( * ? [ son mágicos). No se expande globalmente a los archivos en el directorio actual.
    • [ ab = a? ] [ ab = a? ] : a? glob se expande Entonces puede ser verdadero o falso dependiendo de los archivos en el directorio actual.
    • [ ab = a\? ] [ ab = a\? ] : expansión falsa, no glob
    • = y == son iguales en ambos [ y [[ , pero == es una extensión de Bash.
    • printf 'ab' | grep -Eq 'a.' : Equivalente a POSIX ERE
    • [[ ab =~ 'ab?' ]] [[ ab =~ 'ab?' ]] : falso, pierde magia con ''
    • [[ ab? =~ 'ab?' ]] [[ ab? =~ 'ab?' ]] : cierto
  • =~

    • [[ ab =~ ab? ]] [[ ab =~ ab? ]] : true, coincidencia de expresión regular extendida POSIX ,? no se expande
    • [ a =~ a ] : error de syntax
    • printf 'ab' | grep -Eq 'ab?' : Equivalente POSIX

Recomendación

Prefiero usar siempre [] .

Hay equivalentes POSIX para cada construcción [[ ]] que he visto.

Si usa [[ ]] usted:

  • 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.

Dentro de los corchetes individuales para la prueba de condición (es decir […]), algunos operadores como single = son compatibles con todas las shells, mientras que el uso de operator == no es compatible con algunas de las shells más antiguas.

Dentro de los corchetes dobles para la prueba de condición (es decir [[…]]), no hay diferencia entre usar = o == en las carcasas viejas o nuevas.

Editar: También debería tener en cuenta que: en bash, siempre use corchetes dobles [[…]] si es posible, ya que es más seguro que los corchetes individuales. Ilustraré por qué con el siguiente ejemplo:

 if [ $var == "hello" ]; then 

si $ var pasa a ser nulo / vacío, esto es lo que ve el script:

 if [ == "hello" ]; then 

que romperá tu script La solución es usar corchetes dobles, o siempre recuerde poner comillas alrededor de sus variables ( "$var" ). Los corchetes dobles son una mejor práctica de encoding defensiva.

[[ es una palabra clave bash similar a (pero más poderosa que) el [ comando.

Ver

http://mywiki.wooledge.org/BashFAQ/031 y http://mywiki.wooledge.org/BashGuide/TestsAndConditionals

A menos que esté escribiendo para POSIX sh, le recomendamos [[ .

puede usar los corchetes dobles para la coincidencia de expresiones regulares claras, por ejemplo:

if [[ $1 =~ "foo.*bar" ]] ; then

(siempre y cuando la versión de bash que esté utilizando admita esta syntax)

El manual de Bash dice:

Cuando se usa con [[, los operadores ‘< ' y '>‘ ordenan lexicográficamente usando la configuración regional actual. El comando de prueba utiliza el orden ASCII.

(El comando de prueba es idéntico a [])