Uso de '_' como uma variável de ambiente passada para um comando

1

Do manual do bash

_

At shell startup, set to the absolute pathname used to invoke the shell or shell script being executed as passed in the environment or argument list. Subsequently, expands to the last argument to the previous command, after expansion. Also set to the full pathname used to invoke each command executed and placed in the environment exported to that command. When checking mail, this parameter holds the name of the mail file.

Em relação à sentença em negrito, Stephane disse que

bash, like a few other shells will pass a _ environment variable to commands it executes that contains the path that bash used as the first argument to the execve() system calls.

$ env | grep '^_'
_=/usr/bin/env

Como posso obter o valor da variável de ambiente _ para um comando arbitrário em vez de env , para verificar se seu valor é o nome do caminho do executável ou script para o comando?

Obrigado.

    
por Tim 30.06.2016 / 01:59

3 respostas

6

O valor $_ é visível para o processo filho. A maneira como você lê na criança depende da linguagem que você usa.

por exemplo. em C

#include <stdlib.h>
#include <stdio.h>

main()
{
  char *x=getenv("_");
  printf("%s\n",x);
}

No entanto, um programa não pode contar com $_ sendo definido porque outras camadas podem fazer coisas diferentes.

por exemplo,

$ env -i /bin/bash -c ./a.out
./a.out

$ env -i /bin/ksh -c ./a.out 
*31801*./a.out

$ env -i /bin/sh -c ./a.out 
Segmentation fault (core dumped)

/ bin / sh (que é "dash" neste sistema Ubuntu) não configura $ _ de forma alguma e por isso este simples programa falha. Oops: -)

Seu programa de chamada não pode ver esse valor de $_ . De fato, no shell de chamada $_ é definido como o último parâmetro da linha anterior

$ ls /tmp > /dev/null
$ echo $_
/tmp

$ echo hello
hello
$ echo $_
hello
    
por 30.06.2016 / 02:39
1

Se você estiver executando em um sistema baseado em Linux, poderá examinar o ambiente de um processo lendo o /proc/[pid]/environ pseudo-arquivo, mas somente se o processo ainda estiver em execução e você tiver permissão.

Seu conteúdo é semelhante à saída de env ou printenv , exceto que as variáveis são separadas por caracteres nulos em vez de novas linhas.

man proc e pesquise environ para obter mais informações.

Por exemplo:

$ /bin/sleep 60 &
[1] 25909
$ tr '
perl -nE 'undef $/; say grep /^_=/, split /
$ /bin/sleep 60 &
[1] 25909
$ tr '
perl -nE 'undef $/; say grep /^_=/, split /%pre%/, scalar <>' /proc/$!/environ
' '\n' < /proc/$!/environ | grep '^_=' _=/bin/sleep $
/, scalar <>' /proc/$!/environ
' '\n' < /proc/$!/environ | grep '^_=' _=/bin/sleep $

onde $! se expande para o PID do trabalho mais recentemente colocado em segundo plano.

Isso será mais difícil para programas que terminam rapidamente.

É possível que isso produza um falso positivo se você tiver uma variável de ambiente cujo valor contenha "\n_=" , uma vez que não distingue entre novas linhas que fazem parte do ambiente e novas linhas traduzidas de caracteres nulos. Isso não é provável que seja um problema, mas se for, você precisará de algo um pouco diferente:

%pre%     
por 01.07.2016 / 01:39
1

Isso não é possível (no shell em execução).

Para imprimir um valor de variável de ambiente, você precisa de um comando, use printenv :

$ printenv "LANG"
LANG=en_US.UTF-8

Que relatará o valor da variável como exportada para o ambiente do comando. Ou você usará echo (ou printf, ou imprime) o valor da variável no presente shell em execução:

$ echo "$LANG"
LANG=en_US.UTF-8

Em ambos os casos, um comando foi executado e o valor da variável $_ foi definido para o último argumento do comando executado (se houver algum comando executado).

$ ls
$ echo ".$_."
.--color=auto.
$ echo ".$_."
..--color=auto..
$ echo ".$_."
...--color=auto...

$ bash -c 'echo $_'
/bin/bash

$ bash -c 'ls -l >>/dev/null; echo $_'
-l

Portanto: qualquer comando executado definirá $_ para o shell filho no qual o comando foi executado e impresso como o valor de $_ pelo mesmo shell.

Algumas conchas não usam nem definem um $_ temporal:

$ dash -c 'ls -l >/dev/null; echo ".$_."'
./bin/dash.

Mas isso só revelará o valor do caminho para dash .     ..

    
por 01.07.2016 / 07:16