Diferença entre expansão e substituição na terminologia de script de shell

8

Expansão e substituição parecem ser intercambiáveis ​​no mesmo contexto na linguagem de programação shell. Por exemplo, alguns documentos, como o manual de referência do Bash , o Wiki do Bash Hackers, usam a palavra 'expansão' para explicar ' expansão de parâmetros do shell '. No entanto, alguns outros documentos parecem preferir a palavra 'substituição'. O Advanced Bash-Scripting Guide usa a substituição de parâmetro .

Existe alguma diferença entre 'expansão' e 'substituição' em termos de terminologia de programação de shell?

MS.Kim
fonte
Ambos são válidos em diferentes contextos, por exemplo variable expansion, command substitution. Qual a sua dúvida?
precisa saber é o seguinte
Sem contexto específico, receio que isso seja muito amplo e pouco claro também.
precisa saber é o seguinte
Olhando para a página de manual do bash, em geral a palavra "expansão" parece ser usada se apenas coisas internas do shell estiverem envolvidas, enquanto "substituição" parece ser a preferida para coisas que envolvem processos externos.
Celtschk
Se você tomar o meu conselho, você vai parar de ler esses documentos até que esteja completamente familiarizado com estes: pubs.opengroup.org/onlinepubs/9699919799/utilities/... Quando você é feito com aqueles que você faça man she man set. E quando você tem essas coisas para baixo, faz os documentos específicos do shell.
mikeserv
@ devnull Você está certo. Embora eu coloque o link para o contexto, seria melhor especificar o contexto explicitamente com a pergunta. Vou editar a pergunta para que as pessoas possam entendê-la claramente.
MS.Kim

Respostas:

6

Substituição é quase sinônimo de expansão neste contexto, porque seus significados se sobrepõem. Nenhuma é uma subcategoria completa da outra, embora na seção Manual do GNU você faça referência a substituições que são consideradas como parte de uma expansão geral.

Uma expansão está extraindo o valor de um identificador. Por exemplo, se this=that, quando expandimos this, obtemos that. Uma expansão que não envolve substituição é predeterminada, pois o valor usado já existe e deve ser simplesmente recuperado, embora isso inclua a combinação de valores recuperados / explícitos (como na "expansão aritmética").

Uma substituição cria um valor como resultado de uma operação explícita de entrada / saída. Por exemplo, se this=$(foo bar), thisé o resultado da execução foo bare captura de sua saída. 1 Embora o valor resultante de uma substituição possa ser completamente previsível, ele é diferente do valor recuperado em uma expansão normal, porque na verdade não existe até que a substituição ocorra - ela é produzida.

As substituições têm dois tipos, comando e processo , que são simétricos:

# Command substitution
foo=$(ls)
# Process substitution
wc <(ls)

O "comando" no primeiro é ls, assim como o "processo" no segundo. Podemos dizer que o que está sendo substituído é realmente o fim de um cano. A substituição do processo se sobrepõe ao redirecionamento . No entanto, isso é provavelmente um pouco restritivo demais tecnicamente, o que nos leva à nota de rodapé ...


  1. foo barnesse caso, pode ser uma função shell interna; nesse caso, não há IO entre processos. A existência de embutidos no shell menos obviamente oculta essa diferença. Em termos de conteúdo, a entrada e a saída serão as mesmas.
Cachinhos Dourados
fonte
Eu gosto dessa explicação, mas como se encaixaria na expansão do nome de arquivo , que certamente produz um conjunto de nomes de arquivos como resultado de uma operação (um algoritmo correspondente).
De Novo
Claro, mas para jogar semântica, "extrair o valor de um identificador" (o que chamei de expansão) também é uma operação, portanto, uma substituição? Especialmente porque "existem substituições consideradas parte de uma expansão geral". Ou seja, a relação entre essas palavras não é análoga à distinção entre esquerda e direita. Acho que a expansão do nome de arquivo se encaixa bem na minha definição original de expansão, mas esclareci as coisas sobre as substituições acima para ajudar a tornar mais óbvio o motivo.
Goldilocks
O problema que tive ao traçar essa explicação intuitiva com a expansão do nome de arquivo não era que eu queria que os termos fossem definidos exclusivamente, mas essa expansão de nome de arquivo não parece recuperar um valor vinculado a um identificador. Dentro de um determinado shell, o valor de um determinado globo dependeria de mais do que apenas o globo, e o mesmo globo poderia produzir resultados diferentes em contextos diferentes. Além disso, não há necessidade de vincular o valor para recuperá-lo posteriormente. O relacionamento não é arbitrário (como em foo = "o que você quiser"; echo "$ foo"), mas sim computação e resultado.
De Novo
Suponho que a relação entre expressão e valor na expansão aritmética também não seja (exatamente) arbitrária, mas definitivamente existe apenas um valor para uma dada expansão, independentemente do contexto. Eu posso apenas estar procurando aqui, mas de todas as expansões de shell, a expansão de nome de arquivo parece ser o homem estranho, dada esta explicação.
De
2
set -- arg arg2
echo ${2+"$1"}
 #OUTPUT 
arg

shift
echo ${2+"$1"}
 #OUTPUT

 #there doesn't seem to be anything here

Acho que a diferença geralmente é mínima demais para ser notada - e os termos são frequentemente usados ​​de forma intercambiável. Embora, se você olhar para os dois casos acima, você pode ver que no primeiro exemplo nós substituto $1 para $2, como resultado da expansão da $2. Assim que $2não puder ser expandido, não haverá substituição.

goldilocks faz um bom argumento sobre a existência etérea de substituições. Mais ou menos como o gato de Schrodinger, eu acho. Isso me lembrou algo. Você pode não estar familiarizado com esta forma de expansão de parâmetro especificada pelo POSIX, mas funciona de uma maneira oposta à forma acima:

${var:?if $var is unset or null its \
     parent shell dies and this message is output to stderr}

Agora, às vezes, quero o mesmo comportamento, mas por um setvalor. O POSIX não especifica esse comportamento para nada exatamente. Mas, com um truque ou dois, é simplesmente gerenciado:

N= #N is null
var="any value should fail"
${var:+${N:?we substitute our \$Null var when \$var is expanded}}
  #OUTPUT
sh: line 3: N: we substitute our $Null var when $var is expanded

Mas:

N= #N is null
var=
${var:+${N:?is never substituted}}
  #OUTPUT

#there doesn't seem to be anything here
mikeserv
fonte