aninhado aspas duplas no one-liner altamente votado

17

Uma StackOverflow responde com > 3.5K votos apresenta este one-liner para atribuir a DIR o diretório do script bash atual:

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

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

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

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

Eu entendo o que as aspas duplas em "${BASH_SOURCE[0]}" alcançam, mas qual é o propósito dos outros dois pares de aspas duplas?

Se, por outro lado (e apesar da alta pontuação de votos), o snippet acima está incorreto, qual é o caminho certo para atingir sua intenção nominal?

(Por intenção nominal , quero dizer: coletar o valor retornado por pwd após o primeiro cd -ing para o diretório retornado por dirname "${BASH_SOURCE[0]}" e fazer o cd -ing em um sub-shell, para que o $PWD do shell pai permaneça inalterado).

    
por kjo 14.06.2016 / 04:40

2 respostas

11

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, bash analisa o lado direito da atribuição para uma longa string $( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) , porque as aspas duplas podem aparecer dentro de aspas duplas .

Depois, bash começa a analisar a substituição do comando. Como todos os caracteres após o parêntese de abertura até parênteses envolventes 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, divide-o em duas partes:

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

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

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

    
por 14.06.2016 / 05:31
15

Quando uma pessoa estiver dentro de $(...) , as cotações começarão do zero.

Em outras palavras, "..." e $(...) podem aninhar entre si. A substituição do processo, $(...) , pode conter uma ou mais cadeias de aspas duplas completas . Além disso, cadeias com aspas duplas podem conter uma ou mais substituições de processos completas . Mas, eles não se entrelaçam. Assim, uma string de aspas duplas que começa dentro de uma substituição de processo nunca se estenderá 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]} está entre aspas duplas. Quaisquer citações, duplas ou únicas, fora do $(...) são irrelevantes ao determinar que ${BASH_SOURCE[0]} tem aspas duplas.

O% externo% contém%:

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

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

Veja como as aspas duplas se combinam:

    
por 14.06.2016 / 05:13