Un compañero de trabajo afirmó recientemente en una revisión de código que la construcción [[ ]]
es preferible a [ ]
en construcciones como
if [ "`id -nu`" = "$someuser" ] ; then echo "I love you madly, $someuser" fi
No pudo proporcionar un razonamiento. ¿Hay alguno?
[[
tiene menos sorpresas y generalmente es más seguro de usar. Pero no es portátil: POSIX no especifica lo que hace y solo algunas carcasas lo admiten (además de bash, escuché que ksh también lo admite). Por ejemplo, puedes hacer
[[ -e $b ]]
para probar si existe un archivo. Pero con [
, debe citar $b
, porque divide el argumento y expande cosas como "a*"
(donde [[
toma literalmente)]. Eso también tiene que ver con cómo [
puede ser un progtwig externo y recibe su argumento de manera normal, como cualquier otro progtwig (aunque también puede ser un comando integrado, pero aún así no tiene este manejo especial).
[[
también tiene otras características agradables, como la coincidencia de expresiones regulares con =~
junto con operadores como se conocen en los lenguajes tipo C). Aquí hay una buena página al respecto: ¿Cuál es la diferencia entre la prueba, [
y [[
? y Bash Tests
[[ ]]
tiene más funciones: sugiero que eche un vistazo a la Guía avanzada de scripts de Bash para obtener más información, específicamente la sección del comando de prueba extendida en el Capítulo 7. Pruebas .
Por cierto, como señala la guía, [[ ]]
se introdujo en ksh88 (la versión de 1988 del shell Korn).
Diferencias de comportamiento
Primero, analicemos las diferencias de comportamiento entre ambos. 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. &&
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:
[
es solo un comando regular con un nombre extraño, no hay semántica especial involucrada. ¿ De qué comparador, prueba, corchete o corchete doble es el más rápido? ( http://bashcurescancer.com )
El paréntesis doble es un “comando compuesto” donde la prueba y el paréntesis son incorporados en el shell (y en realidad son el mismo comando). Por lo tanto, el corchete simple y el corchete doble ejecutan un código diferente.
La prueba y el bracket único son los más portátiles ya que existen como comandos separados y externos. Sin embargo, si está utilizando una versión remotamente moderna de BASH, se admite el doble soporte.
Una situación típica en la que no puede usar [[se encuentra en una secuencia de comandos autotools configure.ac, los paréntesis tienen un significado especial y diferente, por lo que deberá usar la test
lugar de [o [[- Tenga en cuenta que la prueba y [son iguales] progtwig.
[[]] los corchetes dobles no están protegidos bajo ciertas versiones de SunOS y las declaraciones de funciones internas no están totalmente protegidas por: GNU bash, versión 2.02.0 (1) – liberación (sparc-sun-solaris2.6)
En pocas palabras, [[es mejor porque no se bifurca otro proceso. Sin corchetes o un solo soporte es más lento que un corchete doble, ya que bifurca otro proceso.