Estoy leyendo ejemplos de bash, if
pero 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, if
pero 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 -o
y 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/bash
o #!/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 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: /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 a
o b
(like +
or 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.
[]
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 [])