Estoy usando GNU bash
4.3.48
. Considere los siguientes dos comandos que solo difieren en un solo signo de dólar.
Comando 1:
echo "(echo " * ")"
Comando 2:
echo "$(echo " * ")"
La salida de ellos es, respectivamente
(echo test.txt ppcg.sh )
y
*
Así que, obviamente, en el primer caso, el *
globo está englobado, lo que significa que la primera comilla va con el segundo para formar un par, y el tercero y el cuarto forman otro par.
En el segundo caso, el *
no está globalizado, y hay exactamente dos espacios adicionales en la salida, uno antes del asterisco y otro después, lo que significa que la segunda comilla va con la tercera y la primera va con el cuarto.
¿Hay otros casos además de la $()
construcción en los que las comillas no coinciden con la siguiente, sino que están anidadas? ¿Está bien documentado este comportamiento? En caso afirmativo, ¿dónde puedo encontrar el documento correspondiente?
Respuestas:
Cualquiera de las construcciones de anidamiento que se pueden interpolar dentro de las cadenas puede tener más cadenas dentro de ellas: se analizan como un nuevo script, hasta el marcador de cierre, e incluso se pueden anidar en varios niveles de profundidad. Todos menos uno de esos comienzan con a
$
. Todos ellos están documentados en una combinación del manual de Bash y la especificación del lenguaje de comandos de shell POSIX.Hay algunos casos de estas construcciones:
Sustitución de comandos con
$( ... )
, como has encontrado. POSIX especifica este comportamiento :Las citas son parte de los scripts de shell válidos, por lo que se permiten con su significado normal.
`
, también.El elemento "palabra" de instancias de sustitución de parámetros avanzados como
${parameter:-word}
. La definición de "palabra" es :, que incluye texto citado e incluso citas mixtas
a"b"c'd'e
, aunque el comportamiento real de las expansiones es un poco más liberal que eso, y por ejemplo${x:-hello world}
también funciona.La expansión aritmética con
$(( ... ))
, aunque es en gran medida inútil allí (pero también puede anidar la sustitución de comandos o expansiones variables, y luego tener comillas útiles dentro de ellas). POSIX afirma que :entonces este comportamiento es explícitamente requerido. Eso significa
echo "abc $((4 "*" 5))"
aritmética, en lugar de globbing.Sin embargo,
$[ ... ]
tenga en cuenta que la expansión aritmética de estilo antiguo no se trata de la misma manera: las comillas serán un error si aparecen, independientemente de si la expansión se cita o no. Este formulario ya no está documentado, y no está destinado a ser utilizado de todos modos.$"..."
, que en realidad usa el"
como elemento central.$"
se trata como una sola unidadHay otro caso de anidación que no puede esperar, que no involucra comillas, que es con expansión de llaves : se
{a,b{c,d},e}
expande a "a bc bd e".${x:-a{b,c}d}
hace no nido, sin embargo; se trata como una sustitución de parámetro que da "a{b,c
", seguido de "d}
". Eso también está documentado :Como regla general, todas las construcciones delimitadas analizan sus cuerpos independientemente del contexto circundante (y las excepciones se tratan como errores ). En esencia, al ver
$(
el código de sustitución de comandos solo le pide al analizador que consuma lo que pueda del cuerpo como si fuera un nuevo programa, y luego verifica que el marcador de terminación esperado (sin escape)
o))
o}
) aparezca una vez que se ejecuta el sub-analizador fuera de las cosas que puede consumir.Si piensa en el funcionamiento de un analizador de descenso recursivo , eso es solo una simple recurrencia al caso base. En realidad, es más fácil de hacer que a la inversa, una vez que tienes la interpolación de cadenas. Independientemente de la técnica de análisis subyacente, los depósitos que soportan estas construcciones dan el mismo resultado.
Puede anidar las citas tan profundamente como desee a través de estas construcciones y funcionará como se espera. Ningún lugar se confundirá al ver una cita en el medio; en cambio, ese será el comienzo de una nueva cadena entre comillas en el contexto interior.
fuente
"blah/blah\n$(cat "${tmpdir}/${filename}.jpdf")"
, ¿por qué la segunda comilla doble no es el final de la primera comilla doble (como lo muestra el resaltado de sintaxis en su respuesta), sino un comienzo de una cadena dentro$(...)
? ¿Es porque el analizador de bash es de arriba hacia abajo, en lugar de de abajo hacia arriba?"${var-"foo"}"
(echo "${-+"*"}"
es el mismo queecho *
en el shell Bourne o Korn, por ejemplo) y el comportamiento se hará claramente no especificado en la próxima versión del estándar . Vea también la discusión en mail-archive.com/[email protected]/msg00167.htmlQuizás mirar los dos ejemplos con
printf
(en lugar deecho
) ayude:Imprime
(echo
(la primera palabra, incluido un espacio final), algunos archivos y la palabra de cierre)
.El paréntesis es solo parte de la cadena citada
(echo
.El asterisco (ahora sin comillas, ya que las dos comillas dobles están emparejadas) se expande como un globo a una lista de archivos coincidentes.
Y luego, el paréntesis de cierre.
Sin embargo, su segundo comando funciona de la siguiente manera:
El
$
inicia una sustitución de comando. Eso comienza de nuevo la cita.Se cita el asterisco
" * "
y eso es lo queecho
genera el comando (aquí es un comando y no una cadena entre comillas) . Finalmente,printf
vuelve a formatear el*
e imprime como< * >
.fuente