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?
bash
if-statement
rkmax
fuente
fuente
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.fuente
[[ ]]
(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 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 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
ob
(like+
orindex
) 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(
.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.fuente
[]
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:
si $ var resulta ser nulo / vacío, entonces esto es lo que ve el script:
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.fuente
[[
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
[[
.fuente
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)
fuente
El manual de Bash dice:
(El comando de prueba es idéntico a [])
fuente