He leído que necesita comillas dobles para expandir variables, por ejemplo
if [ -n "$test" ]; then echo '$test ok'; else echo '$test null'; fi
funcionará como se esperaba, mientras
if [ -n $test ]; then echo '$test ok'; else echo '$test null'; fi
siempre dirá $test okincluso si $testes nulo.
pero entonces, ¿por qué no necesitamos citas echo $test?

echoargumento, se eliminarán los espacios adicionales y las nuevas líneas.Respuestas:
Siempre necesita comillas alrededor de las variables en todos los contextos de la lista , es decir, en todas partes, la variable puede expandirse a múltiples valores a menos que desee los 3 efectos secundarios de dejar una variable sin comillas.
Los contextos de lista incluyen argumentos a comandos simples como
[oecho, lasfor i in <here>asignaciones a matrices ... Hay otros contextos donde las variables también necesitan ser citadas. Lo mejor es siempre citar variables a menos que tenga una muy buena razón para no hacerlo.Piense en la ausencia de comillas (en contextos de lista) como el operador split + glob .
Como si
echo $testfueraecho glob(split("$test")).El comportamiento del shell es confuso para la mayoría de las personas porque en la mayoría de los otros idiomas, se colocan comillas alrededor de cadenas fijas, como
puts("foo"), y no alrededor de variables (likeputs(var)), mientras que en shell es al revés: todo es una cadena en shell, por lo que poner comillas alrededor de todo sería engorroso, ustedecho test, no necesita hacerlo"echo" "test". En shell, las comillas se usan para otra cosa: evitar algún significado especial de algunos caracteres y / o afectar el comportamiento de algunas expansiones.En
[ -n $test ]oecho $test, el shell se dividirá$test(en espacios en blanco por defecto), y luego realizará la generación de nombre de archivo (expandirá todos los*patrones '?' ... a la lista de archivos coincidentes), y luego pasará esa lista de argumentos a los comandos[oecho.Nuevamente, piense en ello como
"[" "-n" glob(split("$test")) "]". Si$testestá vacío o contiene solo espacios en blanco (spc, tab, nl), entonces el operador split + glob devolverá una lista vacía, por lo[ -n $test ]que será"[" "-n" "]", que es una prueba para verificar si "-n" es la cadena vacía o no. Pero imagina lo que hubiera pasado si$testfuera "*" o "= foo" ...En
[ -n "$test" ],[se pasa los cuatro argumentos"[","-n",""y"]"(sin las comillas), que es lo que queremos.Ya sea que haga
echoo[no la diferencia, es solo queechogenera lo mismo, ya sea que haya pasado un argumento vacío o ningún argumento.Consulte también esta respuesta a una pregunta similar para obtener más detalles sobre el
[comando y la[[...]]construcción.fuente
La respuesta de @ h3rrmiller es buena para explicar por qué necesita las comillas para
if(o mejor dicho,[/test), pero en realidad diría que su pregunta es incorrecta.Pruebe los siguientes comandos y verá lo que quiero decir.
Sin las comillas, la sustitución de variables hace que el segundo comando se expanda a:
y los múltiples espacios se colapsan en uno solo:
Con las comillas, se conservan los espacios.
Esto sucede porque cuando se cita un parámetro (si ese parámetro se pasa a
echo,testo algún otro comando), el valor de ese parámetro se envía como un valor a la orden. Si no lo cita, el shell hace su magia normal de buscar espacios en blanco para determinar dónde comienza y dónde termina cada parámetro.Esto también se puede ilustrar con el siguiente programa C (muy, muy simple). Pruebe lo siguiente en la línea de comando (es posible que desee hacerlo en un directorio vacío para no arriesgarse a sobrescribir algo).
y entonces...
Después de ejecutar
paramtest,$?mantendrá el número de parámetros que se pasó (y ese número se imprimirá).fuente
Esto se trata de cómo el shell interpreta la línea antes de ejecutar un programa.
Si la línea se lee
echo I am $USER, el shell la expandeecho I am blrflyechono tiene idea de si el origen del texto es una expansión literal o variable. Del mismo modo, si se lee una líneaecho I am $UNDEFINED, el shell se expandirá$UNDEFINEDen nada y los argumentos de echo lo seránI am, y ese es el final. Dado queechofunciona bien sin argumentos,echo $UNDEFINEDes completamente válido.Su problema con
ifno es realmente conif, porqueifsolo ejecuta el programa y los argumentos que le siguen y ejecuta lathenparte si el programa sale0(o laelseparte si hay una y el programa sale de otro modo0):Cuando
if [ ... ]haces una comparación, no estás usando primitivas integradas en el shell. En realidad, le está ordenando al shell que ejecute un programa llamado[que es un superconjunto muy levetest(1)que requiere que su último argumento sea]. Ambos programas salen0si la condición de prueba se cumplió y1no fue así.La razón por la que algunas pruebas se rompen cuando una variable no está definida es porque
testno ve que está usando una variable. Ergo, se[ $UNDEFINED -eq 2 ]rompe porque cuando el shell termina con él, todos lostestargumentos para ver son-eq 2 ], lo cual no es una prueba válida. Si lo hiciera con algo definido, como[ $DEFINED -ne 0 ], eso funcionaría porque el shell lo expandiría en una prueba válida (por ejemplo,0 -ne 0).Hay una diferencia semántica entre
foo $UNDEFINED bar, que se expande a dos argumentos (fooybar) porque$UNDEFINEDestá a la altura de su nombre. Compare esto confoo "$UNDEFINED" bar, que se expande a tres argumentos (foo, una cadena vacía y `bar). Las citas obligan al shell a interpretarlas como un argumento, ya sea que haya algo entre ellas o no.fuente
Sin comillas
$testpodría expandirse para ser más de una palabra, por lo que debe ser citado para no romper la sintaxis ya que cada interruptor dentro del[comando espera un argumento que es lo que hacen las comillas (lo que se$testexpande en un argumento)La razón por la que no necesita comillas para expandir una variable
echoes porque no espera un argumento. Simplemente imprimirá lo que le digas. Entonces, incluso si se$testexpande a 100 palabras, echo aún lo imprimirá.Echa un vistazo a las trampas de Bash
fuente
echo?echo. ¿Qué te hace pensar lo contrario?echo $testy funciona (genera el valor de $ test)Los parámetros vacíos se eliminan si no se citan:
El comando llamado no ve que haya un parámetro vacío en la línea de comando del shell. Parece que [se define para devolver 0 para -n sin nada siguiente. Por qué siempre.
Las citas también marcan la diferencia para echo, en varios casos:
fuente
echo, es la cáscara. Verías el mismo comportamiento conls. Pruebetouch '*'algo de tiempo si se siente aventurero.:)