comillas dobles anidadas en una sola línea altamente votada


20

Una respuesta de StackOverflow con> 3.5K votos presenta esta línea para asignar al DIRdirectorio del script bash actual:

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

Estoy desconcertado por las comillas dobles anidadas. Por lo que puedo decir, los siguientes fragmentos están entre comillas dobles:

"$( cd "
"${BASH_SOURCE[0]}"
" && pwd )"

... y todo lo demás a la derecha de =(es decir, $( dirnamey )) no está entre comillas. En otras palabras, supongo que los caracteres segundo, cuarto y sexto ""cierran" los caracteres primero, tercero y quinto ", respectivamente.

Entiendo lo que "${BASH_SOURCE[0]}"logran las comillas dobles , pero ¿cuál es el propósito de los otros dos pares de comillas dobles?

Si, por otro lado (y a pesar del alto puntaje de voto), el fragmento anterior es incorrecto, ¿cuál es la forma correcta de lograr su intención nominal?

(Por intención nominal quiero decir: recopilar el valor devuelto por pwddespués de primero cden el directorio devuelto por dirname "${BASH_SOURCE[0]}", y hacer el cd-ing en un sub-shell, para que el $PWDdel shell principal permanezca sin cambios).


1
que es debido a una característica de $ (...): $( here, it's a subshell, but you are writing code as if you were writing it on the "first level" of the shell .... ).
— Olivier Dulac

Vine aquí por el script de instalación de Docker. Para encontrar el nombre de la distribución:lsb_dist="$(. /etc/os-release && echo "$ID")"; echo "$lsb_dist"
— David Tonhofer

Tenga en cuenta que no se necesitan espacios en la línea: también DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"funciona.
— David Tonhofer

Respuestas:


12

Su acertijo no es correcto acerca de cómo bash(y el shell en general) analizó la entrada. En:

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

Primero, bashanalice el lado derecho de la asignación a una cadena larga $( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )porque la comilla doble puede aparecer dentro de las comillas dobles .

Después de eso, bashcomience a analizar la sustitución del comando. Debido a que todos los caracteres que siguen al paréntesis abierto al paréntesis adjunto se usan para construir el comando dentro de la sustitución del comando, obtendrá:

cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd

El shell continúa analizando ese comando compuesto, divídalo en dos partes:

  • cd "$( dirname "${BASH_SOURCE[0]}" )"
  • pwd

Luego, aplica la misma regla de análisis cd "$( dirname "${BASH_SOURCE[0]}" )", pero esta vez, las comillas dobles no son redundantes, pero tienen sentido. Evitan la división de campos en función del resultado $( dirname "${BASH_SOURCE[0]}" )y también la expansión de ${BASH_SOURCE[0]}(En contraste con las comillas dobles más externas, no será necesario en RHS de asignación de variables para prevenirsplit+glob ).


Esta regla se aplica a la sustitución de comandos en todos los shell POSIX . Puede encontrar un rompecabezas más detallado en la sección de Reconocimiento de tokens de la especificación POSIX .


21

Una vez que uno está adentro $(...), las citas comienzan desde cero.

En otras palabras, "..."y $(...)pueden anidar uno dentro del otro. La sustitución de procesos $(...), puede contener una o más cadenas completas entre comillas dobles. Además, las cadenas entre comillas dobles pueden contener una o más sustituciones de proceso completas . Pero no se entrelazan. Por lo tanto, una cadena de comillas dobles que comienza dentro de una sustitución de proceso nunca se extenderá fuera de ella o viceversa.

Entonces, considere:

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

Dentro del interior $(...)está:

dirname "${BASH_SOURCE[0]}"

En lo anterior ${BASH_SOURCE[0]}se cita doblemente. Cualquier comilla, doble o simple, fuera de la, $(...)es irrelevante al determinar que ${BASH_SOURCE[0]}se cita entre comillas dobles.

El exterior $(...)contiene:

cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd

Aquí, la expresión $( dirname "${BASH_SOURCE[0]}" )está entre comillas dobles. El hecho de que haya citas fuera del exterior $(...)es irrelevante cuando se considera lo que está dentro de él. El hecho de que haya citas dentro de lo interno $(...)también es irrelevante.

Así es como coinciden las comillas dobles:

ingrese la descripción de la imagen aquí


¿Qué quiere decir irrelevant? Excepto por el paréntesis más externo, todos los demás tienen su propio significado.
— Cuonglm

44
Y, esta es la razón por la que no debe usar backticks: las reglas de comillas son extremadamente extrañas y no intuitivas.
— Comodín el

La oración "se $(...)une más fuerte que "..."" no tiene sentido. No son operadores infijos, y no hay jerarquía entre ellos (si lo hubiera, significaría que las comillas no pueden estar entre paréntesis o los paréntesis no pueden estar entre comillas, pero ese no es el caso). El término técnico es eso $(…)y "…"nido.
— Gilles 'SO- deja de ser malvado'

@Gilles Muy bien. Acabo de volver a redactar con la esperanza de capturar mejor el concepto.
— John1024
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.