Estoy leyendo ejemplos de bash, ifpero algunos ejemplos están escritos entre corchetes:
if [ -f $param ]
then
#...
fi
otros con corchetes dobles:
if [[ $? -ne 0 ]]
then
start looking for errors in yourlog
fi
¿Cuál es la diferencia?
Estoy leyendo ejemplos de bash, ifpero algunos ejemplos están escritos entre corchetes:
if [ -f $param ]
then
#...
fi
otros con corchetes dobles:
if [[ $? -ne 0 ]]
then
start looking for errors in yourlog
fi
¿Cuál es la diferencia?
Respuestas:
Las []pruebas de condición de cumplimiento posix son simples .
Double [[]]son una extensión del estándar []y son compatibles con bash y otros shells (por ejemplo, zsh, ksh). Admiten operaciones adicionales (así como las operaciones estándar posix). Por ejemplo: en ||lugar de -oy expresiones regulares que coinciden con =~. Se puede encontrar una lista más completa de diferencias en la sección del manual de bash sobre construcciones condicionales .
Úselo []siempre que desee que su secuencia de comandos sea portátil entre shells. Úselo [[]]si desea expresiones condicionales que no son compatibles []y no necesitan ser portables.
[[ ]](por ejemplo, bash con #!/bin/basho #!/usr/bin/env bash), debe usar la opción portátil. Las secuencias de comandos que suponen que / bin / sh admite extensiones como esta se romperán en sistemas operativos como las recientes versiones de Debian y Ubuntu, donde ese no es el caso.
Diferencias de comportamiento
Probado 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 /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.
También hay otras diferencias como =y =~.
En Bashese: [es un comando incorporado y [[es una palabra clave: /ubuntu/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: ¿Cómo probar cadenas para lexicografía menor o igual en Bash?&& 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? ]: a?Glob 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. Sin 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 ao b(like +or 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.
[] debe leerse como Mi preferencia : úsela []si no desea perder la portabilidad . Como se indica aquí : si la portabilidad / conformidad con POSIX o BourneShell es una preocupación, se debe usar la sintaxis anterior. Si, por otro lado, el script requiere BASH, Zsh o KornShell, la nueva sintaxis suele ser más flexible, pero no necesariamente compatible con versiones anteriores. Prefiero ir [[ ab =~ ab? ]]si puedo y no me preocupa la compatibilidad con versiones anteriores queprintf 'ab' | grep -Eq 'ab?'
Dentro de los corchetes individuales para la prueba de condición (es decir, [...]), algunos operadores como single =son compatibles con todos los shells, mientras que el uso del operador ==no es compatible con algunos de los shells más antiguos.
Dentro de los corchetes dobles para la prueba de condición (es decir, [...]]), no hay diferencia entre usar =o ==en conchas viejas o nuevas.
Editar: También debo tener en cuenta que: en bash, siempre use corchetes [...] dobles si es posible, porque es más seguro que los corchetes individuales. Ilustraré por qué con el siguiente ejemplo:
if [ $var == "hello" ]; then
si $ var resulta ser nulo / vacío, entonces esto es lo que ve el script:
if [ == "hello" ]; then
que romperá tu guión. La solución es usar corchetes dobles o siempre recordar poner comillas alrededor de sus variables ( "$var"). Los corchetes dobles son una mejor práctica de codificación 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 ligeras, por ejemplo:
if [[ $1 =~ "foo.*bar" ]] ; then
(siempre que la versión de bash que esté utilizando sea compatible con esta sintaxis)
El manual de Bash dice:
Cuando se usa con [[, los operadores '<' y '>' se ordenan lexicográficamente usando la localización actual. El comando de prueba utiliza el orden ASCII.
(El comando de prueba es idéntico a [])