Considere este trecho:
$ SOMEVAR=AAA
$ echo zzz $SOMEVAR zzz
zzz AAA zzz
Aqui eu defini $SOMEVAR
como AAA
na primeira linha - e quando eu ecoo na segunda linha, obtenho o AAA
conteúdo conforme o esperado.
Mas então, se eu tentar especificar a variável na mesma linha de comando que echo
:
$ SOMEVAR=BBB echo zzz $SOMEVAR zzz
zzz AAA zzz
... Não obtenho BBB
o que esperava - obtenho o valor antigo ( AAA
).
É assim que as coisas deveriam ser? Se sim, como então você pode especificar variáveis como LD_PRELOAD=/... program args ...
e fazer com que funcione? o que estou perdendo?
bash
environment-variables
echo
Sdaau
fonte
fonte
LD_PRELOAD
funciona é que a variável é definida no ambiente do programa - não em sua linha de comando.Respostas:
O que você vê é o comportamento esperado. O problema é que o shell pai avalia
$SOMEVAR
na linha de comando antes de invocar o comando com o ambiente modificado. Você precisa obter a avaliação de$SOMEVAR
adiado até depois que o ambiente for configurado.Suas opções imediatas incluem:
SOMEVAR=BBB eval echo zzz '$SOMEVAR' zzz
.SOMEVAR=BBB sh -c 'echo zzz $SOMEVAR zzz'
.Ambos usam aspas simples para evitar que o shell pai seja avaliado
$SOMEVAR
; ele só é avaliado depois de definido no ambiente (temporariamente, durante o único comando).Outra opção é usar a notação de sub-shell (como também sugerido por Marcus Kuhn em sua resposta ):
A variável é definida apenas no sub-shell
fonte
O problema, revisitado
Francamente, o manual é confuso neste ponto. O manual do GNU Bash diz:
Se você realmente analisar a frase, o que ela está dizendo é que o ambiente para o comando / função foi modificado, mas não o ambiente para o processo pai. Então, isso vai funcionar:
porque o ambiente para o comando env foi modificado antes de ser executado. No entanto, isso não funcionará:
por causa de quando a expansão do parâmetro é executada pelo shell.
Passos do intérprete
Outra parte do problema é que o Bash define essas etapas para seu interpretador:
O que está acontecendo aqui é que os built-ins não têm seu próprio ambiente de execução, portanto, eles nunca veem o ambiente modificado. Além disso, comandos simples (por exemplo, / bin / echo) não ter uma ennvironment modificada (que é por isso que o exemplo env trabalhou), mas a expansão shell está ocorrendo no atual ambiente na etapa # 4.
Em outras palavras, você não está passando 'aaa $ TESTVAR ccc' para / bin / echo; você está passando a string interpolada (conforme expandida no ambiente atual) para / bin / echo. Nesse caso, como o ambiente atual não tem TESTVAR , você simplesmente passa 'aaa ccc' para o comando.
Resumo
A documentação poderia ser muito mais clara. Ainda bem que existe Stack Overflow!
Veja também
http://www.gnu.org/software/bash/manual/bashref.html#Command-Execution-Environment
fonte
FOO=foo eval 'echo $FOO'
imprimefoo
conforme o esperado. Isso significa que você pode fazer coisas comoIFS="..." read ...
.Para conseguir o que deseja, use
Razão:
Você deve separar a atribuição por ponto-e-vírgula ou nova linha do próximo comando, caso contrário, ele não será executado antes que a expansão do parâmetro aconteça para o próximo comando (eco).
Você precisa fazer a atribuição dentro de um ambiente de subshell , para garantir que não persista além da linha atual.
Esta solução é mais curta, mais organizada e mais eficiente do que algumas das outras sugeridas, em particular ela não cria um novo processo.
fonte
(export SOMEVAR=BBB; python -c "from os import getenv; print getenv('SOMEVAR')")
SOMEVAR=BBB python -c "from os import getenv; print getenv('SOMEVAR')"
O motivo é que isso define uma variável de ambiente para uma linha. Mas,
echo
não faz a expansão,bash
faz. Portanto, sua variável é realmente expandida antes que o comando seja executado, mesmo queSOME_VAR
estejaBBB
no contexto do comando echo.Para ver o efeito, você pode fazer algo como:
Aqui, a variável não é expandida até que o processo filho seja executado, portanto, você vê o valor atualizado. se você verificar
SOME_VARIABLE
novamente no shell pai, ainda estaráAAA
, conforme o esperado.fonte
Use um ; para separar instruções que estão na mesma linha.
fonte
LD_PRELOAD
e tal pode funcionar na frente de um executável sem ponto-e-vírgula, porém ... Muito obrigado novamente - saúde!Aqui está uma alternativa:
fonte
&&
ou;
para separar os comandos, a atribuição persiste, o que não é o comportamento desejado do OP. Markus Kuhn tem a versão correta dessa resposta.