En mi entorno Bash, uso variables que contienen espacios, y uso estas variables dentro de la sustitución de comandos. Lamentablemente no puedo encontrar la respuesta en SE.
¿Cuál es la forma correcta de citar mis variables? ¿Y cómo debo hacerlo si están anidados?
DIRNAME=$(dirname "$FILE")
o cito fuera de la sustitución?
DIRNAME="$(dirname $FILE)"
¿o ambos?
DIRNAME="$(dirname "$FILE")"
o uso los ticks de vuelta?
DIRNAME=`dirname "$FILE"`
¿Cuál es la forma correcta de hacer esto? ¿Y cómo puedo verificar fácilmente si las comillas están correctas?
bash
shell
quoting
command-substitution
PrimoCocaína
fuente
fuente
Respuestas:
En orden de peor a mejor:
DIRNAME="$(dirname $FILE)"
no hará lo que quiera si$FILE
contiene espacios en blanco o caracteres de globo\[?*
.DIRNAME=`dirname "$FILE"`
es técnicamente correcto, pero no se recomiendan los backticks para la expansión de comandos debido a la complejidad adicional al anidarlos.DIRNAME=$(dirname "$FILE")
es correcto, pero solo porque esta es una tarea . Si usa la sustitución de comandos en cualquier otro contexto, comoexport DIRNAME=$(dirname "$FILE")
odu $(dirname "$FILE")
, la falta de comillas causará problemas si el resultado de la expansión contiene espacios en blanco o caracteres globales.DIRNAME="$(dirname "$FILE")"
Es la forma recomendada. Puede reemplazarDIRNAME=
con un comando y un espacio sin cambiar nada más, ydirname
recibe la cadena correcta.Para mejorar aún más:
DIRNAME="$(dirname -- "$FILE")"
funciona si$FILE
comienza con un guión.DIRNAME="$(dirname -- "$FILE"; printf x)" && DIRNAME="${DIRNAME%?x}"
funciona incluso si$FILE
termina con una nueva línea, ya que$()
corta las nuevas líneas al final de la salida ydirname
genera una nueva línea después del resultado. Sheeshdirname
, ¿por qué tienes que ser diferente?Puede anidar expansiones de comandos tanto como desee. Con
$()
usted siempre cree un nuevo contexto de cotización, para que pueda hacer cosas como esta:Usted no quiere probar que con acentos abiertos.
fuente
$()
Siempre creas un nuevo contexto de citas", así que es como fuera de las comillas externas. No hay nada más, que yo sepa.Siempre puede mostrar los efectos de las comillas variables con
printf
.División de palabras realizada en
var1
:var1
citado, por lo que no hay división de palabras:Palabra dividida en el
var1
interior$()
, equivalente aecho "hello" "world"
:No hay división de palabras
var1
, no hay problema con no citar el$()
:Palabra dividida de
var1
nuevo:Citando a ambos, la forma más fácil de estar seguro.
Problema global
No citar una variable también puede conducir a una expansión global de su contenido:
Tenga en cuenta que esto sucede después de que la variable se expande solo. No es necesario citar un glob durante la asignación:
Use
set -f
para deshabilitar este comportamiento:Y
set +f
para volver a habilitarlo:fuente
var1='hello * world'
que ilustrar también el problema global.Adición a la respuesta aceptada:
Aunque generalmente estoy de acuerdo con la respuesta de @ l0b0 aquí, sospecho que la colocación de backticks desnudos en la lista de "peor a mejor" es al menos en parte el resultado de la suposición de que
$(...)
está disponible en todas partes. Me doy cuenta de que la pregunta especifica Bash, pero hay muchas ocasiones en las que Bash/bin/sh
parece significar , lo que puede no ser siempre el shell Bourne Again completo.En particular, el shell Bourne simple no sabrá qué hacer
$(...)
, por lo que los scripts que afirman ser compatibles con él (por ejemplo, a través de una#!/bin/sh
línea shebang) probablemente se comportarán mal si en realidad son ejecutados por lo "real"/bin/sh
. interés especial cuando, por ejemplo, produce scripts de inicio o empaqueta pre y post scripts, y puede colocar uno en un lugar sorprendente durante la instalación de un sistema base.Si algo de eso suena como algo que está planeando hacer con esta variable, el anidamiento probablemente sea menos preocupante que tener el script realmente ejecutado de manera predecible. Cuando es un caso bastante simple y la portabilidad es una preocupación, incluso si espero que el script generalmente se ejecute en sistemas donde
/bin/sh
está Bash, a menudo tiendo a usar backticks por esta razón, con múltiples asignaciones en lugar de anidar.Habiendo dicho todo eso, la ubicuidad de las conchas que implementan
$(...)
(Bash, Dash, et al.), Nos deja en un buen lugar para seguir con la sintaxis POSIX más bonita, más fácil de anidar y más recientemente preferida en la mayoría de los casos, para todas las razones que @ l0b0 menciona.Aparte: esto también ha aparecido ocasionalmente en StackOverflow -
fuente