Quando `_` é uma variável de ambiente de um shell bash?

10

O Bash Manual diz (página de manual, minha ênfase):

Quando o Bash chama um comando externo, a variável $_é configurada para o nome do caminho completo do comando e passada para esse comando em seu ambiente.

E ( Parâmetros especiais ):

_

( $_, um sublinhado.) Na inicialização do shell, defina o nome do caminho absoluto usado para chamar o script do shell ou shell sendo executado conforme passado na lista de ambiente ou argumento. Posteriormente, expande para o último argumento para o comando anterior, após a expansão. Defina também o nome do caminho completo usado para chamar cada comando executado e colocado no ambiente exportado para esse comando. Ao verificar o correio, este parâmetro mantém o nome do arquivo de correio.

  1. Em um shell bash, eu corro:

    $ bash
    $ export | grep '_=' 

    De acordo com o manual, _deve ser uma variável de ambiente do novo shell bash. exportdeve gerar todas as variáveis ​​de ambiente do novo shell bash, mas não gera _. Então, eu me pergunto se _é uma variável de ambiente do novo shell bash?

  2. Na verdade, em qualquer shell bash, acontece a mesma coisa

    $ export | grep '_='

    não produz nada. Então, eu me pergunto se _alguma vez é uma variável de ambiente de um shell bash?

  3. Para comparação:

    $ dash
    $ export  | grep '_='        
    export _='/bin/dash'

Meu post é inspirado no comentário de Mike e na resposta de Stephane .

Tim
fonte
1
É uma variável do shell e é passada para o ambiente do comando ; não é necessariamente exportado para o ambiente do shell . exporté um builtin, mas se você o usar printenv _, ele mostrará como foi chamado: /usr/bin/printenvneste sistema.
Toby Speight
Note-se que bash -c export | grep _=(a partir Bash), vai mostrar como o shell pai invocou o bashcomando, mesmo que $_não está definido no pai.
Toby Speight
Consulte também unix.stackexchange.com/questions/293302 .
JdeBP

Respostas:

13

Sim, _é uma variável de ambiente do novo shell Bash; você pode ver isso executando

tr '\0' '\n' < /proc/$$/environ | grep _=

dentro do shell: mostra o conteúdo do ambiente inicial do shell. Você não o verá no primeiro shell, porque não havia um shell anterior para defini-lo antes de iniciar.

A expansão $_dentro do Bash refere-se ao _parâmetro especial, que se expande para o último argumento do comando anterior. (Internamente, o Bash lida com isso usando uma _variável de shell, que é atualizada toda vez que um comando é analisado, mas isso é realmente um detalhe da implementação. É "não exportado" toda vez que um comando é analisado. ) exportNão é exibido _porque não é uma variável que é marcada como exportada; no entanto, você pode vê-lo na saída de set.

No primeiro exemplo, o novo shell Bash analisa e executa os comandos em seus arquivos de inicialização, portanto, quando em execução explore | grep '-=', _já foi substituído e marcado como não exportado.

No dashexemplo, ele não parece executar nenhum arquivo de inicialização; portanto, você está vendo a variável como uma variável de ambiente definida pelo Bash antes da execução dash.

Stephen Kitt
fonte
Obrigado. No novo shell bash, por que não produz export | grep '_='nada? No shell bash original, por que não produz tr '\0' '\n' < /proc/$$/environ | grep _=nada?
Tim
9

exportsem argumentos lista todas as variáveis exportadas . _não é uma variável, mas é listado como um parâmetro especial .

Um tanto confuso, _também seria um nome válido para uma variável , diferente dos nomes dos outros parâmetros especiais. Pelo menos o Bash 4.4 permite atribuições a ele, sem queixas. Simplesmente não é útil porque o efeito especial substitui imediatamente o valor.

ilkkachu
fonte
2
Divirta-se tentando usar _como uma variável ;-). É efetivamente somente para gravação e o valor é perdido imediatamente.
Stephen Kitt
1
Além disso, internamente o Bash trata _como uma variável, e é por isso que aparece na saída de set. No entanto, não pode ser marcado como exportado, tanto quanto eu possa determinar.
Stephen Kitt
2
@StephenKitt, mas o Bash 4.4 permite marcá-lo como somente leitura. Ou um número inteiro. Com resultados um tanto hilariantes.
Ilkkachu 09/04
1
Ah, boa descoberta, isso é divertido!
Stephen Kitt
5

Nem todas as variáveis ​​de shell são marcadas como exportadas, como você pode ver na saída de declare -p.

Não faz sentido bashmarcar $_como exportado porque adiciona automaticamente essa variável ao ambiente dos processos filhos, mas com um valor diferente daquele que ela possui no shell (naquele momento).

Exibi-lo como exportado apenas confundiria o usuário sobre o que aconteceria com o ambiente de comandos externos.

Todas as "variáveis ​​de tempo de execução" BASH*não são exportadas.

Hauke ​​Laging
fonte