O que é essa sintaxe shell / bash: someVariable = someValue someCommand [duplicate]

26

Um de meus colegas de trabalho me forneceu uma sintaxe Bash com a qual eu não estou familiarizado. Meu Google foo falhou em descobrir o que faz e por que / quando eu deveria usá-lo.

O comando que ele me enviou foi desta forma:

someVariable=something command

Inicialmente, achei que isso era equivalente ao seguinte:

someVariable=something ; command

Ou

someVariable=something 
command

Mas isso não parece ser o caso. Exemplos:

[Jan-03 11:26][~]$ # Look at the environment variable BAZ. It is currently empty
[Jan-03 11:26][~]$ echo $BAZ

[Jan-03 11:27][~]$ # Try running a command of the same format    
[Jan-03 11:27][~]$ BAZ=jake echo $BAZ

[Jan-03 11:27][~]$    
[Jan-03 11:27][~]$ # Now, echo BAZ again. It is still empty:    
[Jan-03 11:27][~]$ echo $BAZ

[Jan-03 11:27][~]$    
[Jan-03 11:28][~]$    
[Jan-03 11:28][~]$ # If we add a semi-colon to the command, we get dramatically different results:
[Jan-03 11:28][~]$ BAZ=jake ; echo $BAZ
jake
[Jan-03 11:28][~]$
[Jan-03 11:28][~]$ # And we can see that the variable is actually set:
[Jan-03 11:29][~]$ echo $BAZ
jake
[Jan-03 11:29][~]$

O que essa sintaxe faz? O que acontece com a variável que foi definida? Por que isso funciona?

    
por sixtyfootersdude 03.01.2017 / 17:33

4 respostas

38

Isso é equivalente a:

( export someVariable=something; command )

Isso torna someVariable uma variável de ambiente, com o valor atribuído, mas apenas para o comando que está sendo executado.

Aqui estão as partes relevantes do manual bash :

Simple Commands

A simple command is a sequence of optional variable assignments followed by blank-separated words and redirections, and terminated by a control operator. The first word specifies the command to be executed, and is passed as argument zero. The remaining words are passed as arguments to the invoked command.

(...)

Simple Command Expansion

If no command name results [from command expansion], the variable assignments affect the current shell environment. Otherwise, the variables are added to the environment of the executed command and do not affect the current shell environment.

Observação: tenha em mente que isso não é específico de bash , mas especificado por POSIX .

Editar - Resumiu a discussão a partir dos comentários na resposta

O motivo BAZ=JAKE echo $BAZ , não imprime O JAKE é porque a substituição de variáveis é feita antes de qualquer outra coisa. Se você ignorar a substituição de variável, isso se comportará como esperado:

$ echo_baz() { echo "[$BAZ]"; }
$ BAZ=Jake echo_baz
[Jake]
$ echo_baz
[]
    
por 03.01.2017 / 17:49
16

Estas são atribuições de variáveis no contexto de comandos simples . Como xhienne mencionou, para comandos externos eles são equivalentes a exportar o (s) valor (es) atribuído (s) durante a duração do comando.

Em seus exemplos, você está usando um comando interno, portanto, o comportamento não é o mesmo: as atribuições afetam o ambiente atual, mas se o efeito dura após a execução do comando interno não ser especificado. Para entender seus exemplos, você precisa saber que a expansão de parâmetros acontece antes que as variáveis sejam manipuladas; assim com

 BAZ=jake echo $BAZ

o shell primeiro expande $BAZ (resultando em nada), depois define BAZ para jake e finalmente executa

 echo

, que imprime uma linha vazia. (Então o shell esquece BAZ como mostra seu echo $BAZ subseqüente.)

 BAZ=jake; echo $BAZ

é interpretado como dois comandos: primeiro a variável BAZ é definida no ambiente atual, então echo $BAZ é expandida para echo jake e executada.

    
por 03.01.2017 / 17:55
5

Existem algumas coisas importantes que acontecem aqui:

  • Como explicado no manual de referência do bash , Simple Command Expansion, seção "Se nenhum nome de comando resultar, as atribuições de variáveis afetam o ambiente de shell atual. Caso contrário, as variáveis serão adicionadas ao ambiente do comando executado e não afetarão o ambiente de shell atual." Assim, quando você diz var="something" command arg1 arg2 , o comando será executado com var no ambiente do comando e desaparecendo após command sair. A demonstração disso é simples - acesse o ambiente do comando a partir do comando:

    $ BAZ="jake" python -c "import os; print os.environ['BAZ']"                                                              
    jake
    

    Isso não é nada para se surpreender. Essa sintaxe é freqüentemente usada para executar programas com ambiente modificado. Meus colegas usuários unix.stackexchange.com e askubuntu.com reconhecerão este exemplo: se o usuário usar o idioma alemão, e você só fala em inglês, você pode pedir que eles reproduzam o problema que estão tendo e obtenham resultados em inglês da seguinte forma:

    LC_ALL=C command
    

    Note também que o acesso ao ambiente não é específico de python . Isso pode ser feito com C ou qualquer outra linguagem de programação. Acontece que era a minha "arma de escolha" agora e usada apenas para essa demonstração.

  • A expansão da variável ocorre antes de qualquer coisa ser executada. Assim, quando você executa algo como BAZ="foo" echo $BAZ , o shell examina seu ambiente primeiro, não encontra nenhuma variável BAZ e, portanto, deixa $BAZ empty. Demonstração simples disso é:

    $ BAZ="jake" python -c "import sys; print 'ARG:',sys.argv[1]" $BAZ                                                       
    ARG:
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
    IndexError: list index out of range
    

É importante notar também que a distinção de BAZ=jake; echo $BAZ , que é duas instruções de comando separadas, e aqui BAZ=jake permanecerá no ambiente da shell. O caso de uso depende de suas intenções. Se você pretende executar mais de um programa que precisa de tal variável, talvez seja desejável export dessa variável. Se você precisar apenas dessa hora específica, as atribuições de variáveis anteriores podem ser preferíveis.

    
por 04.01.2017 / 03:35
2

Em palavras simples:

BAZ=jake echo $BAZ

não produz nada porque variable substitution ocorre primeiro em um comando. O que significa que, a primeira coisa que acontece nessa linha de comando é $BAZ será substituída pelo valor real com o qual a variável BAZ foi definida anteriormente (se houver). Lembre-se de que isso acontece mesmo antes do shell considerar BAZ=jake na mesma linha de comando. Antes da execução de nosso comando, como BAZ não tem nenhum valor atribuído e como BAZ=jake é considerado somente após a resolução de $BAZ , $BAZ não resolve nenhum valor. E, portanto, echo $BAZ não produz nada.

BAZ=jake é apenas parte do comando dado (o shell não irá considerá-lo como uma variável de ambiente) e isso é mais útil, se algum processo, que é executado como parte da mesma linha de comando, usa essa variável %código%. E o valor de BAZ , BAZ é volátil depois que a execução do comando é concluída.

Por exemplo: jake , onde o comando ]# LD_LIBRARY_PATH="new_path" ldconfig refere-se internamente à variável ldconfig e não há nenhuma expansão de variável nessa linha de comando diferente da anterior.

Para outro caso:

BAZ=jake; echo $BAZ  

Eles são dois comandos diferentes, dados em uma única linha. É tão bom quanto executar um após o outro.

    
por 11.01.2017 / 08:01