Un compañero de trabajo afirmó recientemente en una revisión de código que la [[ ]]
construcción es preferible [ ]
a las construcciones como
if [ "`id -nu`" = "$someuser" ] ; then
echo "I love you madly, $someuser"
fi
No pudo proporcionar una justificación. ¿Hay uno?
bash
if-statement
syntax
Leonard
fuente
fuente
[[
a él, el código es bueno y claro, pero recuerde ese día cuando portará sus scripts en el sistema con un shell predeterminado que no es ,bash
oksh
etc.[
es más feo, engorroso, pero funciona comoAK-47
en cualquier situación.Respuestas:
[[
tiene menos sorpresas y generalmente es más seguro de usar. Pero no es portátil: POSIX no especifica lo que hace y solo algunos shells lo admiten (además de bash, escuché que ksh también lo admite). Por ejemplo, puedes hacerpara probar si existe un archivo. Pero con
[
, tienes que citar$b
, porque divide el argumento y expande cosas como"a*"
(donde lo[[
lleva literalmente). Eso también tiene que ver con cómo[
puede ser un programa externo y recibe su argumento normalmente como cualquier otro programa (aunque también puede ser un programa incorporado, pero aún no tiene este manejo especial).[[
también tiene algunas otras características interesantes, como la coincidencia de expresiones regulares=~
con operadores similares a los conocidos en lenguajes tipo C. Aquí hay una buena página al respecto: ¿Cuál es la diferencia entre prueba[
y[[
? y pruebas de golpefuente
[[ ]]
pero lo interpreta con el mismo significado que[ ]
.#!/bin/sh
pero luego los cambio para usarlos#!/bin/bash
tan pronto como confío en alguna característica específica de BASH, para denotar que ya no es Bourne shell portable.Diferencias de comportamiento
Algunas diferencias 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 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 queX
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⁵divisió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⁴, 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. No hay 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
ob
(like+
oindex
) y hace una comparación numérica sia
y seb
parecen a enteros decimales.expr "x$a" '<' "x$b"
trabaja alrededor de ambos.³ y también falla para algunos valores de
a
ob
like!
or(
.Bas en bash 3.2 y superior y la compatibilidad proporcionada a bash 3.1 no está habilitada (como con
BASH_COMPAT=3.1
)⁵ 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.fuente
[
por las mismas razones.[[ ]]
tiene más funciones: le sugiero que eche un vistazo a la Guía avanzada de secuencias de comandos de Bash para obtener más información, específicamente la sección de comando de prueba extendido 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).fuente
¿ Desde qué comparador, prueba, paréntesis o paréntesis doble es el más rápido? ( http://bashcurescancer.com )
fuente
[[
podría traer. Pero entonces, soy un viejo pedo de la vieja escuela :-)[
ytest
aunque también existen versiones externas.PS1=...crazy stuff...
y / o$PROMPT_COMMAND
); para estos, no quiero ningún retraso perceptible en la ejecución del script.apt-get update
si han pasado más de X horas desde la última vez que se ejecutó. Es un gran alivio cuando uno puede dejar la portabilidad fuera de la lista ya demasiado larga de restricciones para el código.Si te gusta seguir la guía de estilo de Google :
Prueba,
[
y[[
fuente
[[ -d ~ ]]
devuelve verdadero (lo que implica que~
se expandió a/home/user
) Creo que Google debería haber sido más preciso en su escritura.Una situación típica en la que no puede usar
[[
es en un script configure.ac de autotools, allí los corchetes tienen un significado especial y diferente, por lo que tendrá que usar entest
lugar de[
o[[
- Tenga en cuenta que prueba y[
son el mismo programa.fuente
[
ser definido como una función de shell POSIX?[[]] los corchetes dobles no son compatibles con ciertas versiones de SunOS y no son totalmente compatibles con las declaraciones de funciones internas de: GNU bash, versión 2.02.0 (1) -release (sparc-sun-solaris2.6)
fuente
En pocas palabras, [[es mejor porque no bifurca otro proceso. Ningún paréntesis o un solo paréntesis es más lento que uno doble porque bifurca otro proceso.
fuente
type [
para ver esto.[[
, a diferencia de[
, es la sintaxis interpretada por el intérprete de línea de comandos bash. En bash, intente escribirtype [[
. unix4linux es correcto que, aunque las[
pruebas de Bourne-shell clásicas completan un nuevo proceso para determinar el valor de verdad, la[[
sintaxis (tomada de ksh por bash, zsh, etc.) no lo hace.[
está integrado tanto en Bash como en Dash (/bin/sh
en todas las distribuciones de Linux derivadas de Debian).