virgolette doppie annidate in una sola riga altamente votata


20

Una risposta StackOverflow con> 3.5K voti presenta questo one-liner per l'assegnazione alla DIRdirectory dell'attuale script bash:

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

Sono perplesso dalle doppie virgolette nidificate. Per quanto ne so, i seguenti frammenti sono tra virgolette:

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

... e tutto il resto a destra di =(ie $( dirnamee )) non è quotato. In altre parole, suppongo che il 2o, 4o e 6o "carattere "chiudano" rispettivamente il 1o, 3o e 5o "carattere.

Capisco cosa "${BASH_SOURCE[0]}"ottengono le doppie virgolette , ma qual è lo scopo delle altre due coppie di virgolette?

Se, d'altra parte (e nonostante il punteggio più alto), lo snippet sopra riportato non è corretto, qual è il modo giusto per raggiungere il suo intento nominale?

(Per intento nominale intendo: raccogliere il valore restituito pwddopo il primo cd-ing nella directory restituita da dirname "${BASH_SOURCE[0]}", e fare il cd-ing in una sotto-shell, in modo che la $PWDshell madre rimanga invariata).


1
è a causa di una caratteristica di $ (...): $( 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,

Sono venuto qui per via dello script di installazione della finestra mobile. Per trovare il nome della distro:lsb_dist="$(. /etc/os-release && echo "$ID")"; echo "$lsb_dist"
David Tonhofer,

Nota che non sono necessari spazi nella linea: DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"funziona anche.
David Tonhofer,

Risposte:


12

Il tuo puzzle non ha ragione su come bash(e la shell in generale) ha analizzato l'input. Nel:

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

Innanzitutto, bashanalizzare il lato destro dell'assegnazione a una stringa lunga $( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )perché le virgolette doppie possono apparire tra virgolette doppie .

Successivamente, bashinizia ad analizzare la sostituzione del comando. Poiché tutti i caratteri che seguono la parentesi aperta tra parentesi chiusa vengono utilizzati per costruire il comando all'interno della sostituzione del comando, otterrai:

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

La shell continua ad analizzare quel comando composto, suddividendolo in due parti:

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

Quindi applicare la stessa regola di analisi per cd "$( dirname "${BASH_SOURCE[0]}" )", ma questa volta le virgolette doppie non sono ridondanti, ma hanno senso. Impediscono la divisione del campo a seguito di $( dirname "${BASH_SOURCE[0]}" ), e anche l'espansione di ${BASH_SOURCE[0]}(Contrariamente alle virgolette più doppie esterne, non sarà necessario in RHS di assegnazione variabile per impediresplit+glob ).


Questa regola si applica alla sostituzione dei comandi in tutta la shell POSIX . Un puzzle più dettagliato che puoi leggere nella sezione Riconoscimento token delle specifiche POSIX .


21

Una volta dentro $(...), la citazione ricomincia da capo.

In altre parole, "..."e $(...)possono annidarsi l' uno nell'altro. La sostituzione del processo $(...), può contenere una o più stringhe complete tra virgolette. Inoltre, le stringhe tra virgolette doppie possono contenere una o più sostituzioni di processo complete . Ma non si intrecciano. Pertanto, una stringa tra virgolette che inizia all'interno di una sostituzione di processo non si estenderà mai al di fuori di essa o viceversa.

Quindi, considera:

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

All'interno $(...)è:

dirname "${BASH_SOURCE[0]}"

Quanto sopra ${BASH_SOURCE[0]}è tra virgolette. Eventuali virgolette, doppie o singole, al di fuori del $(...)sono irrilevanti quando si determina che ${BASH_SOURCE[0]}sono tra virgolette doppie.

L'esterno $(...)contiene:

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

Qui, l'espressione $( dirname "${BASH_SOURCE[0]}" )è racchiusa tra virgolette. Il fatto che ci siano virgolette fuori dall'esterno $(...)è irrilevante quando si considera ciò che è al suo interno. Anche il fatto che ci siano virgolette all'interno $(...)è irrilevante.

Ecco come corrispondono le virgolette doppie:

inserisci qui la descrizione dell'immagine


Cosa intendi irrelevant? Ad eccezione della maggior parte delle parentesi esterne, tutte le altre hanno un loro significato.
cuonglm

4
Ed è per questo che non dovresti usare i backtick: le regole di quotazione sono estremamente strane e non intuitive.
Wildcard il

La frase "è $(...)più stretta di "..."" non ha senso. Non sono operatori di infissione e non esiste una gerarchia tra di loro (se ci fosse, ciò significherebbe che entrambe le virgolette non possono essere racchiuse tra parentesi o tra parentesi, ma non è così). Il termine tecnico è questo $(…)e "…"nidificano.
Gilles 'SO- smetti di essere malvagio' il

@Gilles Molto bene. Ho appena riformulato la speranza di catturare meglio il concetto.
Giovanni 1024
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.