En esta pregunta, alguien informa un problema al usar un documento aquí con una palabra delimitadora citada dentro de la $(...)
sustitución de comando , donde una barra invertida \
al final de una línea dentro del documento desencadena la continuación de la línea de unión de nueva línea , mientras que el mismo documento aquí fuera de la sustitución de comando funciona como se esperaba .
Aquí hay un documento de ejemplo simplificado:
cat <<'EOT'
abc ` def
ghi \
jkl
EOT
Esto incluye una barra de retroceso y una barra invertida al final de una línea. Se cita el delimitador, por lo que no se producen expansiones dentro del cuerpo. En todos los Bourne-alikes puedo encontrar esta salida de los contenidos textualmente. Si pongo el mismo documento dentro de una sustitución de comando de la siguiente manera:
x=$(cat <<'EOT'
abc ` def
ghi \
jkl
EOT
)
echo "$x"
entonces ya no se comportan de manera idéntica:
dash
,ash
,zsh
,ksh93
, BusyBoxash
,mksh
y SunOS 5.10 POSIXsh
todos dan los contenidos literales del documento, como antes.- Bash 3.2 da un error de sintaxis para un backtick sin igual. Con backticks coincidentes, intenta ejecutar el contenido como un comando.
- Bash 4.3 colapsa "ghi" y "jkl" en una sola línea, pero no tiene ningún error. La
--posix
opción no afecta esto. Kusalananda me dice (¡gracias!) Que sepdksh
comporta de la misma manera .
En la pregunta original, dije que esto era un error en el analizador de Bash. ¿Lo es? [Actualización: sí ] El texto relevante de POSIX (todo de la definición del lenguaje de comandos de Shell) que puedo encontrar es:
- §2.6.3 Sustitución de comandos :
Con el formulario $ (comando), todos los caracteres que siguen el paréntesis abierto al paréntesis de cierre coincidente constituyen el comando. Se puede usar cualquier script de shell válido para el comando , excepto un script que consista únicamente en redirecciones que produzcan resultados no especificados.
- §2.7.4 Aquí-Documento :
Si se cita una parte de la palabra , el delimitador se formará mediante la eliminación de la cita en la palabra , y las líneas del documento aquí no se expandirán.
- §2.2.1 Carácter de escape (barra invertida) :
Si un <newline> sigue al <backslash>, el shell interpretará esto como una continuación de línea. Las <backslash> y <newline> se eliminarán antes de dividir la entrada en tokens.
- §2.3 Reconocimiento de tokens :
Cuando la gramática ha reconocido un token io_here (ver Gramática de Shell ), una o más de las líneas posteriores que siguen inmediatamente al siguiente token NEWLINE forman el cuerpo de uno o más documentos aquí y se analizarán de acuerdo con las reglas de Aquí. Documento .
Cuando no está procesando un io_here , el shell dividirá su entrada en tokens aplicando la primera regla aplicable a continuación al siguiente carácter en su entrada. ...
...
- Si el carácter actual es <backslash>, comillas simples o comillas dobles y no se cita, afectará la cita para los caracteres posteriores hasta el final del texto citado. Las reglas para las citas son como se describen en las citas . Durante el reconocimiento de tokens, no se realizarán sustituciones, y el token resultante contendrá exactamente los caracteres que aparecen en la entrada (excepto para la unión de <línea nueva>), sin modificar, incluidas las comillas o operadores de sustitución incluidos o incluidos, entre el final y el final. del texto citado.
Mi interpretación de esto es que todos los caracteres posteriores $(
hasta la terminación )
comprenden el script de shell, textualmente; aparece un documento aquí, por lo que el procesamiento del documento aquí ocurre en lugar de la tokenización ordinaria; el documento aquí tiene un delimitador citado, lo que significa que su contenido se procesa textualmente; y el personaje de escape nunca entra en juego. Sin embargo, puedo ver un argumento de que este caso simplemente no se aborda y que ambos comportamientos son permisibles. Es posible que también haya omitido algún texto relevante en alguna parte.
- ¿Esta situación se aclara en otra parte?
- ¿En qué debería poder confiar un script portátil (en teoría)?
- ¿El tratamiento específico de alguno de estos shells (Bash 3.2 / Bash 4.3 / todos los demás) es obligatorio según el estándar? ¿Prohibido? ¿Permitido?
fuente
echo "$x"
, pero cualquier forma de inspeccionar la variable funciona. He editado esa línea en la parte inferior.$(...)
por lo que sea esa salida ... Ahora, cuando ejecuta el comando en su ejemplo en una subshell (enbash
) sí genera el resultado esperado. Es solo cuando lo convierte en sustitución de comando que colapsa "ghi" y "jkl". Así que esto es un error de la OMIRespuestas:
Esto fue preguntado en la lista de correo de Bash, y el responsable confirmó que era un error
También mencionaron que el texto en POSIX "no es necesariamente ambiguo, pero requiere una lectura atenta", por lo que solicité una aclaración al respecto. Su respuesta, incluida una descripción del problema y la interpretación de la norma, fue la siguiente:
fuente