¿Cuál es la diferencia entre usar [[ condition ]]
and [ condition ]
or (( condition ))
and ( condition )
? ¿En qué escenario necesitamos utilizar cualquiera de estos?
(( 10 > 9 ))
funciona pero(( 10 -gt 9 ))
no[[ 10 -gt 9 ]]
funciona pero[[ 10 > 9 ]]
no
Respuesta1
((...))
es el caparazónaritméticaconstruir. Los operadores que puede utilizar están documentados en el manual:6.5 Aritmética de Shell
(...)
es unagrupamientoconstrucción que ejecuta los comandos contenidos en un subshell:3.2.4.3 Comandos de agrupación
[...]
es la construcción condicional "heredada". La documentación está en6.4 Expresiones condicionales de Bash
[[...]]
hace todo lo que [...]
hace. La diferencia es que la división de palabras y la expansión global no se realizan para las variables internas, [[...]]
por lo que citar las variables no es tan crucial. Además, [[
puede hacerla coincidencia de patronescon el ==
operador ycoincidencia de expresiones regularescon el =~
operador.
La razón [[ 10 > 9 ]]
que le da un resultado inesperado es que el >
operador que está dentro [[...]]
es paracomparación de cadenasy la cadena "10" es "menor que" la cadena "9".
Respuesta2
Acerca de ((…))
y(…)
Como se indica enesta otra respuesta, ((…))
es la construcción aritmética del shell (unabashismo) y (…)
ejecuta comandos en un subshell. Son muy diferentes entre sí y de [ … ]
o [[ … ]]
.
Por otro lado [ … ]
y [[ … ]]
son muy similares en casos simples; pueden estar confundidos. El resto de esta respuesta se concentra en [ … ]
y [[ … ]]
.
nota formal
Mis objetivos aquí son:
- para elaborar sobrediferencias y similitudes entre
[ … ]
y[[ … ]]
; - para proporcionar una respuesta canónica en el tema de
[ … ]
vs[[ … ]]
, de modo que las preguntas que puedan responderse con "[
no es[[
" se puedan vincular aquí; - para proporcionar una respuesta lo suficientemente exhaustiva, de modo que los usuarios ya no se sientan tentados a publicar respuestas que se centren en una única diferencia cada una.
Qué es [
?
[
realiza una prueba.El propósito de
[
es probar algo (por ejemplo, si existe algún archivo) y devolver el estado de salida cero si la prueba tiene éxito, distinto de cero en caso contrario.[
es un comando.[
es un nombre de comando comocat
oecho
.[
(comoecho
) es una función incorporada en Bash, pero esto solo significa que se puede ejecutar sin generar un proceso adicional; aún se comporta como un comando. Probablemente exista un[
ejecutable independiente en su sistema (p. ej./bin/[
); pruebatype -a [
en Bash para averiguarlo.[
requiere un espacio después.Como comando,
[
toma argumentos. Como ocurre con cualquier otro comando, los argumentos deben estar separados entre sí y del nombre del comando.[foo
es un nombre de comando diferente, no es equivalente a[ foo
(de manera similar y más obviamenteechoHello world
no lo esecho Hello world
). Ciertamente necesitas un espacio (o una tabulación) después[
.[
requiere]
.[
requiere]
como último argumento, de lo contrario se niega a funcionar. Esto es sólo para[ … ]
resaltar como un bloque, como si fuera una sintaxis especial; pero no es una sintaxis especial. Para pasar]
como último argumento necesita un espacio (o una tabulación) antes. A modo de comparación: el último argumento[ … bar]
esbar]
cual no es]
, por lo que[ … bar]
no es un comando válido.[
es (casi) comotest
.[ … ]
es equivalente atest …
. En otras palabras, puede convertir cualquier[
comando en untest
comando eliminando]
y cambiando el nombre del comando. Y puede convertir cualquiertest
comando en un[
comando cambiando el nombre del comando y agregando]
.[
no es especial.Es bueno recordar
[
que no es especial, es sólo un nombre un tanto sofisticado para un comando. Si reconoces esto, no te sorprenderá el hecho de quetodoel análisis y procesamiento del shell lo haceantesLa ejecución de un comando (test
oecho
,ls
etc.) también ocurre si el comando es[
. En particular:[
no sabe si citó alguno de sus argumentos, obtiene argumentos después de que el shell elimina las comillas.Sin comillas y sin escape
&&
o||
entre[
y]
no se interpreta como un argumento para[
. En otras palabras,[ … || … ]
se interpreta como[ …
(inválido porque no hay]
) y… ]
(un comando separado, sea lo que…
sea) conectado lógicamente con||
, exactamente comocommand1 || command2
.
[
está especificado por POSIX.Ahí está elEspecificación POSIX para
[
/test
. Puedes llamar[
al portátil. Notas:- Algunas primarias son extensiones, otras están marcadas como obsoletas. Por ejemplo, nuestro código no válido (
[ … || … ]
) se puede corregir como[ … -o … ]
, pero como-o
es obsoleto, una solución mejor es[ … ] || [ … ]
. - Las implementaciones pueden respaldar más primarias. El
[
incorporado en Bash lo hace (verhelp test
); el[
binario (como/bin/[
) en su sistema operativo puede (verman test
).
- Algunas primarias son extensiones, otras están marcadas como obsoletas. Por ejemplo, nuestro código no válido (
Qué es [[
? ¿En qué se [[
diferencia [
?
Notas:
- La pregunta está etiquetada.intento, ahora estamos hablando de[[
en fiesta.
- Los párrafos numerados de este apartado corresponden a los párrafos numerados del apartado anterior.
(semejanza)
[[
realiza una prueba.El propósito de
[[
es probar algo (por ejemplo, si existe algún archivo) y devolver el estado de salida cero si la prueba tiene éxito, distinto de cero en caso contrario.[[
Puede probar cualquier cosa[
y más.(diferencia)
[[
es una palabra clave.es
[[
una palabra clave de shell (invocatype [[
en Bash para confirmar esto). Al igual que la palabra clave[
incorporada,[[
pertenece a Bash; perono escomportarse como una orden.(semejanza)
[[
requiere un espacio después.(O una pestaña).
(semejanza)
[[
requiere]]
.[[
requiere]]
más adelante en el código, sin embargo, no es solo para[[ … ]]
resaltar como un bloque. Es una sintaxis especial (una diferencia, llegaremos a ella). Necesitas un espacio (o una tabulación) antes]]
.(diferencia)No existe ningún comando de apariencia normal equivalente a
[[
.No hay ningún otro comando/palabra clave/lo que sea que pueda reemplazar
[[
de la misma maneratest
que puede reemplazar[
.(diferencia)
[[
esespecial.[[
cambia la forma en que el shell analiza e interpreta el código, hasta el correspondiente]]
. El análisis y procesamiento normal que realiza el shell antes de ejecutar[
ortest
(oecho
,ls
etc.) no se aplica dentro de[[ … ]]
. En particular:[[
esSepa si citó alguno de sus "argumentos". Las variables entre comillas dobles no son necesarias (aunque normalmentees), pero en algunos casos, poner una cadena (o una variable) entre comillas dobles marca la diferencia (consulteesta respuestadonde menciona "el lado derecho de=
o==
o!=
o=~
").&&
o||
entre[[
y]]
pertenece a la[[ … ]]
construcción.[[ … || … ]]
puede ser un fragmento de código válido, prácticamente equivalente a[[ … ]] || [[ … ]]
.
(diferencia)
[[
no está especificado por POSIX.[[
no es[[
Funciona en Bash, no funciona en puresh
. Es posible que otros shells lo admitan[[
(por ejemplo, Zsh), pero[[
pueden ser diferentes al[[
de Bash.[[
no está diseñado para cumplir con la especificación de[
/test
. En muchos casos, reemplazar[
con[[
y]
con]]
le dará un[[ … ]]
fragmento equivalente al[ … ]
fragmento original; pero no siempre,a vecesEs necesario ajustar el interior. Así que no cambies[
a[[
ciegas. Cambiar a ciegas[[
es[
aún más riesgoso porque hay pruebas[[
que se pueden hacer y[
no se pueden hacer.
Otras notas:
Ni
[
ni[[
es parte de laif … then …
sintaxis. Recuerdeif
que solo prueba el estado de salida de algún código.if true; then …
es válido,if sleep 5; then …
es válido, de manera similarif [ … ]; then …
oif [[ … ]]; then …
es válido (si la parte[ … ]
o[[ … ]]
es en sí misma un fragmento válido).Dado que
((…))
o también devuelve algún estado de salida (eso depende de lo que hay dentro), también(…)
se puede usar después .if
Personalmente prefiero utilizarlo
[
para cualquier prueba[
que pueda realizar fácilmente, recurriendo a él[[
cuando sea realmente necesario. De esta manera no me acostumbro a lo no portátil[[
y sé lo que puedo hacer en un shell no tan rico como Bash.El
[
ejecutable de su sistema operativo no es necesariamente equivalente al[
integrado en su Bash. Si[
Bash lo invoca, el incorporado hará el trabajo. Si[
lo invoca otra cosa, entonces el ejecutable hará el trabajo. Por ejemplo,find … -exec [ … ] …
utiliza el ejecutable. No existe un[[
ejecutable estándar (al menos en los sistemas que conozco), por lo quefind … -exec [[ … ]] …
nunca funcionará. Si hubiera un[[
ejecutable, tendría que comportarse como un comando y no podría imitar la palabra clave.
Respuesta3
Hay una gran diferencia entre [ ] y [[ ]]:
a=0;
if [ $a = 1 -a $(grep ERR 1.log|wc -l) -ne 0 ];then
echo "error";
fi
cuando se utiliza [ ], el operador y -a no admite la evaluación de cortocircuito. En el código anterior, incluso la primera condición devuelve falso, la segunda condición aún se puede evaluar. Si el archivo 1.log no existe, se quejará "No existe tal archivo o directorio".
Pero para [[ ]]:
a=0
if [[ $a = 1 && $(grep ERR 1.log|wc -l) -ne 0 ];then
echo "error"
fi
Incluso el archivo "1.log" no existe, estará bien porque la segunda condición no será evaluada ya que la primera condición es falsa.
Respuesta4
Habría puesto esto en un comentario, pero todavía no puedo hacerlo.
Una diferencia que he notado entre [] y [[]] es que en el primero es posible utilizar comparaciones múltiples.
La misma comparación arroja un error de sintaxis en [[]]
a=1
b=2
Esto funciona:
$ [ "$a" -gt 0 -a "$b" -gt "$a" ] && { echo '[b>a>0]'; }
[b>a>0]
Esto no funciona:
$ [[ $a -gt 0 -a $b -gt $a ]] && { echo '[[b>a>0]]'; }
-bash: syntax error in conditional expression
-bash: syntax error near `-a'
Realmente no he profundizado para ver por qué es así, pero cuando uso comparaciones múltiples, uso [].