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.