Eu estou usando GNU bash
4.3.48
. Considere os dois comandos a seguir que diferem apenas por um único cifrão.
Comando 1:
echo "(echo " * ")"
Comando 2:
echo "$(echo " * ")"
A saída deles são, respectivamente
(echo test.txt ppcg.sh )
e
*
Então, obviamente, no primeiro caso, *
é globbed, o que significa que a primeira aspas vai com a segunda para formar um par, e a terceira e a quarta formam outro par.
No segundo caso *
, ele não é globulado e há exatamente dois espaços extras na saída, um antes do asterisco e um depois, o que significa que a segunda aspas vai com o terceiro e a primeira com o quarto.
Além da $()
construção, existem outros casos em que as aspas não coincidem com a próxima, mas estão aninhadas? Esse comportamento está bem documentado e, em caso afirmativo, onde posso encontrar o documento correspondente?
Respostas:
Qualquer uma das construções de aninhamento que podem ser interpoladas dentro de cadeias de caracteres pode ter outras cadeias dentro delas: elas são analisadas como um novo script, até o marcador de fechamento, e podem até ser aninhadas em vários níveis. Todos, exceto um daqueles, começam com a
$
. Todos eles estão documentados em uma combinação do manual do Bash e da especificação da linguagem de comandos do shell POSIX.Existem alguns casos dessas construções:
Substituição de comando com
$( ... )
, como você encontrou. POSIX especifica este comportamento :As cotações fazem parte de scripts de shell válidos, portanto, são permitidas com seu significado normal.
`
também.O elemento "word" das instâncias avançadas de substituição de parâmetros, como
${parameter:-word}
. A definição de "palavra" é :- que inclui texto citado e até citações mistas
a"b"c'd'e
- embora o comportamento real das expansões seja um pouco mais liberal do que isso, e por exemplo${x:-hello world}
também funcione.Expansão aritmética com
$(( ... ))
, embora seja amplamente inútil lá (mas você também pode aninhar substituição de comando ou expansões variáveis, e depois ter aspas úteis dentro delas). O POSIX afirma que :portanto, esse comportamento é explicitamente necessário. Isso significa
echo "abc $((4 "*" 5))"
aritmética, em vez de globbing.Observe que a
$[ ... ]
expansão aritmética de estilo antigo não é tratada da mesma maneira: as aspas serão um erro se aparecerem, independentemente de a expansão ser citada ou não. Este formulário não está mais documentado e não deve ser usado de qualquer maneira.$"..."
, que na verdade usa o"
como elemento principal.$"
é tratado como uma única unidade.Há um outro caso de aninhamento que você não pode esperar, sem envolver cotações, que é a expansão entre chaves :
{a,b{c,d},e}
expande para "a bc bd e".${x:-a{b,c}d}
faz não ninho, no entanto; é tratado como uma substituição de parâmetro, fornecendo "a{b,c
", seguido de "d}
". Isso também está documentado :Como regra geral, todas as construções delimitadas analisam seus corpos independentemente do contexto circundante (e as exceções são tratadas como bugs ). Em essência, ao ver
$(
o código de substituição de comando, apenas solicita ao analisador que consuma o que pode do corpo como se fosse um novo programa e verifica se o marcador final esperado (um sem escape)
ou))
ou}
) aparece quando o sub-analisador é executado das coisas que pode consumir.Se você pensar no funcionamento de um analisador de descida recursiva , isso é apenas uma recursão simples para o caso base. Na verdade, é mais fácil de fazer do que o contrário, quando você tem interpolação de strings. Independentemente da técnica de análise subjacente, as conchas que suportam essas construções fornecem o mesmo resultado.
Você pode aninhar a citação o quanto quiser por meio dessas construções e funcionará conforme o esperado. Nenhum lugar ficará confuso ao ver uma citação no meio; em vez disso, será o início de uma nova string entre aspas no contexto interior.
fonte
"blah/blah\n$(cat "${tmpdir}/${filename}.jpdf")"
, por que a segunda citação dupla não é o fim da primeira citação dupla (como mostra a sintaxe destacada em sua resposta), mas o início de uma cadeia de caracteres dentro$(...)
? É porque o analisador do bash é de cima para baixo, em vez de de baixo para cima?"${var-"foo"}"
(echo "${-+"*"}"
é o mesmo queecho *
no shell Bourne ou Korn, por exemplo) e o comportamento será tornado claramente não especificado na próxima versão do padrão . Veja também a discussão em mail-archive.com/[email protected]/msg00167.htmlTalvez examinar os dois exemplos com
printf
(em vez deecho
) ajude:Imprime
(echo
(a primeira palavra, incluindo um espaço à direita), alguns arquivos e a palavra final)
.O parêntese é apenas parte da cadeia de caracteres citada
(echo
.O asterisco (agora sem aspas, pois as duas aspas duplas são emparelhadas) é expandido como um globo para uma lista de arquivos correspondentes.
E então, o parêntese de fechamento.
No entanto, seu segundo comando funciona da seguinte maneira:
O
$
inicia uma substituição de comando. Isso começa de novo a citação.O asterisco é citado
" * "
e é isso que o comando (aqui é um comando e não uma string entre aspas)echo
gera. Finalmente,printf
re-formata*
e imprime como< * >
.fonte