Estoy confundido con el uso de corchetes simples o dobles. Mira este código:
dir="/home/mazimi/VirtualBox VMs"
if [[ -d ${dir} ]]; then
echo "yep"
fi
Funciona perfectamente aunque la cadena contiene un espacio. Pero cuando lo cambio a un solo soporte:
dir="/home/mazimi/VirtualBox VMs"
if [ -d ${dir} ]; then
echo "yep"
fi
Dice:
./script.sh: line 5: [: /home/mazimi/VirtualBox: binary operator expected
Cuando lo cambio a:
dir="/home/mazimi/VirtualBox VMs"
if [ -d "${dir}" ]; then
echo "yep"
fi
Funciona bien. ¿Alguien puede explicar lo que está pasando? ¿Cuándo debo asignar comillas dobles alrededor de variables como "${var}"
para evitar problemas causados por espacios?
Respuestas:
El único soporte
[
es en realidad un alias para eltest
comando, es no sintaxis.Una de las desventajas (de muchos) del paréntesis simple es que si uno o más de los operandos que está tratando de evaluar devuelven una cadena vacía, se quejará de que esperaba dos operandos (binario). Es por eso que ves que la gente lo hace
[ x$foo = x$blah ]
, lasx
garantías de que el operando nunca se evaluará en una cadena vacía.El doble soporte
[[ ]]
, por otro lado, es sintaxis y es mucho más capaz que[ ]
. Como descubrió, no tiene el problema de un solo operando y también permite más sintaxis tipo C con los>, <, >=, <=, !=, ==, &&, ||
operadores.Mi recomendación es la siguiente: si su intérprete es
#!/bin/bash
, entonces siempre use[[ ]]
Es importante señalar que
[[ ]]
no es compatible con todas las conchas POSIX, sin embargo muchas conchas que apoyan tales comozsh
yksh
, además debash
fuente
$foo
es!
o(
o-n
... Ese problema no está destinado a ser un problema con shells POSIX donde el número de argumentos (al lado[
y]
) no es mayor que cuatro.[ x$foo = x$blah ]
es tan incorrecto como[ $foo = $bar ]
.[ "$foo" = "$bar" ]
es correcto en cualquier shell compatible con POSIX,[ "x$foo" = "x$bar" ]
funcionaría en cualquier shell similar a Bourne, perox
no es para los casos en que tiene cadenas vacías, sino dónde$foo
puede estar!
o-n
...[
no es precisamente un alias paratest
. Si lo fuera, entoncestest
aceptaría un corchete de cierre.test -n foo ]
. Perotest
no lo hace, y[
requiere uno.[
es idéntico atest
todos los demás aspectos, pero no es así comoalias
funciona. Bash describe[
ytest
como shell incorporado , pero[[
como una palabra clave de shell .>=
y<=
El
[
comando es un comando ordinario. Aunque la mayoría de los shells lo proporcionan como una eficiencia incorporada, obedece las reglas sintácticas normales del shell.[
es exactamente equivalente atest
, excepto que[
requiere un]
como último argumento ytest
no lo hace.Los corchetes dobles
[[ … ]]
son sintaxis especial. Se introdujeron en ksh (varios años después[
) porque[
puede ser problemático de usar correctamente y[[
permite algunas nuevas adiciones agradables que usan caracteres especiales de shell. Por ejemplo, puedes escribirporque toda la expresión condicional es analizada por el shell, mientras
[ $x = foo && $y = bar ]
que primero se dividiría en dos comandos[ $x = foo
y se$y = bar ]
separaría por el&&
operador. Del mismo modo, los corchetes dobles permiten cosas como la sintaxis de coincidencia de patrones, por ejemplo,[[ $x == a* ]]
para probar si el valor dex
comienza cona
; entre paréntesis, esto se expandiríaa*
a la lista de archivos cuyos nombres comienzana
en el directorio actual. Los corchetes dobles se introdujeron por primera vez en ksh y solo están disponibles en ksh, bash y zsh.Dentro de los corchetes simples, debe usar comillas dobles alrededor de sustituciones variables, como en la mayoría de los otros lugares, porque son solo argumentos para un comando (que resulta ser el
[
comando). Dentro de los corchetes dobles, no necesita comillas dobles, ya que el shell no divide ni engloba palabras: analiza una expresión condicional, no un comando.Sin embargo, una excepción es
[[ $var1 = "$var2" ]]
cuando necesita las comillas si desea hacer una comparación de cadena byte a byte, de lo contrario,$var2
sería un patrón para comparar$var1
.Una cosa que no puede hacer
[[ … ]]
es usar una variable como operador. Por ejemplo, esto es perfectamente legal (pero rara vez útil):En tu ejemplo
el comando dentro de la
if
es[
con los 4 argumentos-d
,/home/mazimi/VirtualBox
,VMs
y]
. El shell analiza-d /home/mazimi/VirtualBox
y luego no sabe qué hacerVMs
. Debería evitar la división de palabras${dir}
para obtener un comando bien formado.En términos generales, siempre use comillas dobles alrededor de las sustituciones de variables y comandos a menos que sepa que desea dividir y pegar palabras en el resultado. Los principales lugares donde es seguro no usar las comillas dobles son:
foo=$bar
(pero tenga en cuenta que necesita las comillas dobles enexport "foo=$bar"
o en asignaciones de matriz comoarray=("$a" "$b")
);case
declaración:case $foo in …
;=
o de==
operador (a menos que usted desea que la coincidencia de patrones):[[ $x = "$y" ]]
.En todo esto, es correcto usar comillas dobles, por lo que es mejor omitir las reglas avanzadas y usar las comillas todo el tiempo.
fuente
[
hecho es del Sistema III en 1981 , pensé que era más viejo.Implícito en esta pregunta es
${variable_name}
no significa lo que crees que hace ...... si cree que tiene algo que ver con problemas causados por espacios (en valores variables). es bueno para esto:
${variable_name}
¡y nada más! 1 nosirve de nada a menos que lo esté siguiendo inmediatamente con un carácter que podría ser parte de un nombre de variable: una letra (-o-), un guión bajo () o un dígito (-). E incluso entonces, puedes solucionarlo:
${variable_name}
A
Z
a
z
_
0
9
No estoy tratando de desalentar su uso,
echo "${bar}d"
es probable que sea la mejor solución aquí, sino de disuadir a las personas de depender de llaves en lugar de citas, o aplicar llaves instintivamente y luego preguntar: “Ahora, ¿también necesito citas ? " Siempre debe usar comillas a menos que tenga una buena razón para no hacerlo, y esté seguro de saber lo que está haciendo._________________
1 Excepto, por supuesto, el hecho de que las formas más elegantes de expansión de parámetros , por ejemplo, y se basan en la sintaxis. Además, es necesario utilizar , etc., para hacer referencia a los días 10, 11, etc., parámetros posicionales - cotizaciones no le ayudará con eso.
${parameter:-[word]}
${parameter%[word]}
${parameter}
${10}
${11}
fuente
Para manejar espacios y caracteres especiales en blanco en variables, siempre debe rodearlos con comillas dobles. Establecer un IFS adecuado también es una buena práctica.
Recomendado: http://www.dwheeler.com/essays/filenames-in-shell.html
fuente