aspas duplas aninhadas em uma linha altamente votada


20

Uma resposta StackOverflow com mais de 3,5 mil votos apresenta este recurso para atribuir ao DIRdiretório do script bash atual:

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

Estou intrigado com as aspas duplas aninhadas. Tanto quanto posso dizer, os seguintes fragmentos são citados duas vezes:

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

... e tudo o mais à direita do =(ie $( dirnamee )) não é citado. Em outras palavras, suponho que os caracteres 2, 4 e 6 "fechem os caracteres 1, 3 e 5 ", respectivamente.

Entendo o que as aspas duplas "${BASH_SOURCE[0]}"alcançam, mas qual é o objetivo dos outros dois pares de aspas duplas?

Se, por outro lado (e não obstante a alta pontuação dos votos), o trecho acima estiver incorreto, qual é o caminho certo para atingir sua intenção nominal?

(Por intenção nominal, quero dizer: colete o valor retornado pwddepois de first cd-ing no diretório retornado por dirname "${BASH_SOURCE[0]}"e faça cd-ing em um sub shell, para que o $PWDshell pai permaneça inalterado).


11
é por causa de uma 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

Eu vim aqui por causa do script de instalação do docker. Para encontrar o nome da distribuição:lsb_dist="$(. /etc/os-release && echo "$ID")"; echo "$lsb_dist"
David Tonhofer

Observe que os espaços na linha não são necessários: também DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"funciona.
David Tonhofer

Respostas:


12

Seu quebra-cabeça não está certo sobre como bash(e o shell em geral) analisou a entrada. Em:

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

Primeiro, bashanalise o lado direito da atribuição em uma sequência longa, $( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )pois aspas duplas podem aparecer dentro de aspas duplas .

Depois disso, bashcomece a analisar a substituição do comando. Como todos os caracteres que seguem parênteses abertos a parênteses anexos são usados ​​para construir o comando dentro da substituição de comando, você obterá:

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

O shell continua analisando esse comando composto, divida-o em duas partes:

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

Em seguida, aplicando a mesma regra de análise para cd "$( dirname "${BASH_SOURCE[0]}" )", mas desta vez, aspas duplas não são redundantes, mas fazem sentido. Eles impedem a divisão do campo no resultado de $( dirname "${BASH_SOURCE[0]}" ), e também a expansão de ${BASH_SOURCE[0]}(Em contraste com as aspas duplas mais externas, não é necessário no RHS da atribuição de variáveis ​​para impedirsplit+glob ).


Esta regra se aplica à substituição de comandos em todos os shell POSIX . Um quebra-cabeça com mais detalhes você pode ler na seção Reconhecimento de token da especificação POSIX .


21

Uma vez dentro $(...), as citações começam do zero.

Em outras palavras, "..."e $(...)podem aninhar um dentro do outro. A substituição do processo,, $(...)pode conter uma ou mais seqüências completas de aspas duplas. Além disso, cadeias de caracteres com aspas duplas podem conter uma ou mais substituições de processo completas . Mas eles não se entrelaçam. Portanto, uma string de aspas duplas que inicia dentro de uma substituição de processo nunca se estende para fora dela ou vice-versa.

Então, considere:

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

Dentro do interior $(...)é:

dirname "${BASH_SOURCE[0]}"

No acima ${BASH_SOURCE[0]}é citado duplo. Quaisquer aspas, duplas ou simples, fora da $(...)são irrelevantes ao determinar que ${BASH_SOURCE[0]}são aspas duplas.

O exterior $(...)contém:

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

Aqui, a expressão $( dirname "${BASH_SOURCE[0]}" )está entre aspas duplas. O fato de haver aspas fora do exterior $(...)é irrelevante quando se considera o que está dentro dele. O fato de existirem aspas no interior $(...)também é irrelevante.

Aqui está como as aspas duplas coincidem:

insira a descrição da imagem aqui


Como assim irrelevant? Exceto pela maioria dos parênteses externos, todos os outros têm seu próprio significado.
amigos estão dizendo sobre cuonglm

4
E é por isso que você não deve usar backticks: as regras de cotação são extremamente estranhas e não intuitivas.
Curinga

A frase " $(...)se prende mais do que "..."" não faz sentido. Eles não são operadores infix, e não há hierarquia entre eles (se houvesse, isso significaria que as aspas não podem estar entre parênteses ou parênteses não podem estar entre aspas, mas esse não é o caso). O termo técnico é isso $(…)e "…"ninho.
Gilles 'SO- stop be evil'

@ Gilles Muito bom. Eu apenas reescrevi na esperança de capturar melhor o conceito.
John1024
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.