Por que “A = 10 echo $ A” não imprime 10?

24

Este comando:

A=10 echo $A

imprime uma linha vazia. Por que não 10 ? Por que a configuração do ambiente temporário in-loco não funciona?

Eu quero saber o motivo e a explicação, e não a solução.

eu usei

LANG=C gcc ...

para forçar o gcc a usar o idioma de fallback (inglês) em vez do idioma do sistema (chinês). Então eu suponho que um prefixo VAR=value irá configurar um ambiente temporário para o comando que o segue. Mas parece que eu tenho algum mal entendido.

    
por Earth Engine 28.05.2014 / 13:25

3 respostas

21

É uma questão da ordem em que as diferentes etapas de avaliação de um comando acontecem.

A=10 echo $A primeiro analisa o comando em um comando simples composto de três palavras A=10 , echo e $A . Então cada palavra sofre uma substituição variável, isto é, a transformação de expansões variáveis como $A em seus valores (estou omitindo etapas que não fazem nada visível).

Se A tiver o valor foo inicialmente, o resultado das etapas de expansão será um comando simples que ainda tem três palavras: A=10 , echo e foo . (O shell também lembra neste ponto quais caracteres estavam inicialmente entre aspas - neste caso, nenhum.) O próximo passo é executar o comando. Como A=10 começa com um nome de variável válido seguido por um sinal de igual, ele é tratado como uma atribuição; a variável A está definida como 10 no shell e no ambiente durante a execução do comando. (Normalmente você precisa escrever export A para ter A no ambiente e não apenas como uma variável shell; isso é uma exceção.) A próxima palavra não é uma atribuição, então é tratada como um nome de comando -no comando). O comando echo não depende de nenhuma variável, portanto A=10 echo $A tem exatamente o mesmo efeito que echo $A .

Se você quiser definir uma variável apenas para a duração de um comando, mas levando a atribuição em consideração enquanto executa o comando, você pode usar um subshell. Um subshell, indicado por parênteses, faz com que todas as mudanças de estado (atribuições de variáveis, diretório atual, definições de funções, etc.) sejam locais para o subshell.

(A=10; echo $A)

Faça esse export A=10 se você quiser exportar a variável para o ambiente para que ela seja vista por programas externos.

    
por Gilles 29.05.2014 / 03:00
36

Quando você usa LANG=C gcc ... , o que acontece é que o shell define LANG para o ambiente de gcc somente , e não para o atual ambiente em si ( veja nota ). Então, depois que gcc terminar, LANG estará de volta ao seu valor anterior (ou não definido).

Além disso, quando você usa A=10 echo $A , é o shell que substitui $ A, não echo, e essa substituição (chamada "expansão") acontece antes da instrução é avaliado (incluindo a atribuição), portanto, para funcionar como esperado, o valor de A já deve estar definido no ambiente atual anterior a essa declaração.

É por isso que A=10 echo $A não funciona como esperado: A=10 será definido para echo, mas echo ignora internamente o valor da variável de ambiente A . E $A é substituído pelo valor definido no shell atual (que não é nenhum), e então passado como um argumento para echo.

Portanto, sua suposição está correta: VAR=value command faz funcionar, mas isso só é relevante se command internamente usar VAR. Caso contrário, você ainda pode passar value como um argumento para command , mas os argumentos são substituídos pelo shell atual , então eles devem ser definidos antes do uso: VAR=value; command "$VAR"

Se você souber criar um script executável, tente isso como um teste:

#!/bin/sh
echo "1st argument is "
echo "A is $A"

Salve como testscript e tente:

$ A=5; A=10 testscript "$A"; echo "$A"
1st argument is 5
A is 10
5

Por último, mas não menos importante, vale a pena conhecer a diferença entre variáveis shell e ambiente e programar argumentos .

Aqui estão algumas boas referências:

.

(*) Nota: tecnicamente, o shell também é definido no ambiente atual e eis o porquê: Alguns comandos, como echo , read e test , são integrações de shell e, como tal, não geram um processo filho. Eles correm no ambiente atual. Mas o shell cuida para que a atribuição só dure até que o comando esteja em execução, então, para todos os efeitos práticos, o efeito é o mesmo: a atribuição é vista apenas por esse único comando.

    
por MestreLion 28.05.2014 / 13:37
2

Uma forma possivelmente limpa de fazer o que você aparentemente deseja é emitir o comando:

A=10 eval 'echo $A'

O que, na verdade, adiará a substituição do valor 10 pelo lugar de $ A para um contexto posterior (isto é, "dentro" do eval, que já sabe sobre a atribuição). Note que as aspas simples são essenciais. Tal construção comunica claramente a atribuição ao comando desejado (echo, neste caso) sem correr o risco de poluir seu ambiente atual.

    
por nhokka 29.05.2014 / 07:48