posix shell: imprime lista de nomes de variáveis ​​de ambiente (sem valores)

11

De uma maneira compatível com posix que funciona com várias implementações, como posso imprimir a lista de variáveis ​​de ambiente definidas atualmente sem seus valores?

Em algumas implementações (mksh, freebsd / bin / sh), apenas o uso exportpor si só caberá na conta:

$ export
FOO2
FOO

Mas para algumas outras implementações (bash, zsh, dash), exporttambém mostra o valor. Com o bash, por exemplo:

$ export
export FOO2='as  df\
  asdk=fja:\
asd=fa\
asdf'
export FOO='sjfkasjfd  kjasdf:\
   asdkj=fkajdsf:\
       :askjfkajsf=asdfkj:\
   safdkj'
$ printenv | sed -n l
FOO2=as\tdf\$
  asdk=fja:\$
asd=fa\$
asdf$
FOO=sjfkasjfd  kjasdf:\$
   asdkj=fkajdsf:\$
\t:askjfkajsf=asdfkj:\$
   safdkj$

Outras opções, como envou printenvnão, têm opções para imprimir apenas os nomes das variáveis ​​sem valores, pelo menos não nas plataformas linux e freebsd que eu tentei.

Tubulação para awk / sed / etc. ou aparar a lista com técnicas de expansão de parâmetros (por exemplo, ${foo%%=*}) é aceitável, mas precisa trabalhar com valores que podem abranger linhas e ter um =espaço em branco no valor (veja o exemplo acima).

Respostas específicas para implementações específicas de shell são interessantes, mas estou procurando principalmente por algo que seja compatível entre implementações.

Juan
fonte
2
Se você estiver analisando algo, vá com a saída export -pespecificada pelo POSIX para gerar uma saída que também é adequada para entrada no shell.
Kusalananda
Não preciso de nada para inserir em um shell. Eu só quero os nomes das variáveis ​​de ambiente. Portanto, a quantidade extra (por exemplo, a palavra 'exportar' na frente de cada linha) teria que ser removida de qualquer maneira. Por que eu gostaria de usar export -pisso?
Juan Juan
1
Você gostaria de usá-lo export -pporque isso forneceria uma saída consistente em todos os shells POSIX, que você disse que queria.
Kusalananda
Eu quero uma solução que imprima apenas os nomes das variáveis ​​que sejam uma solução consistente entre os shells. export -pnão se encaixa no primeiro requisito - imprimir apenas nomes de variáveis ​​sem valores.
Juan
Se você estiver analisando algo, vá com a saída de export -p. Não vou escrever essa análise, porque, no caso geral, também seria necessário fazer uma análise de cotação adequada, caso você tenha uma variável cujo valor seja algo parecido hello\nexport var=value. Um dos poucos outros comandos que fornecerá uma saída consistente em todos os shells POSIX é env, mas essa saída é mais difícil de analisar, pois falta um export =pouco.
Kusalananda

Respostas:

9

É bem fácil no awk.

awk 'BEGIN{for(v in ENVIRON) print v}'

No entanto, cuidado com algumas implementações do awk que adicionam variáveis ​​de ambiente próprias (por exemplo, GNU awk adiciona AWKPATHe adiciona AWKLIBPATHa ENVIRON).

A saída é ambígua se o nome de uma variável de ambiente contiver uma nova linha, o que é extremamente incomum, mas tecnicamente possível. Uma solução sh pura seria difícil. Sua melhor aposta é começar, export -pmas massagear com sh puro é difícil. Você pode usar o sed para massagear a saída e export -p, em seguida, usar evalo shell para remover o que foi citado. Bash e zsh imprimem prefixos não padrão.

report () { echo "${1%%=*}"; };
eval "$(export -p | sed "s/^export /report /;
                         s/^declare -x /report /;
                         s/typeset -x /report /")"

Observe que, dependendo do shell, export -ppode ou não mostrar variáveis ​​cujo nome não é válido no shell e, se não for, pode ou não citar os nomes corretamente. Por exemplo, dash, mksh e zsh omitem variáveis ​​cujo nome inclui uma nova linha, o busyBox dash e o ksh93 os imprimem em bruto e o bash os imprime em bruto sem seu valor. Se você precisar se defender de informações não confiáveis, não confie em uma solução POSIX pura e, definitivamente, não invoque evalnada derivado da saída de export -p.

Gilles 'SO- parar de ser mau'
fonte
Não tenho certeza de quão "fácil" é realmente com sed (1) com valores de múltiplas linhas - eu gostaria de ver isso. Mas obrigado pelo método awk (1). Eu acho que essa é a maneira mais portátil até agora (embora eu ache que não exitseja necessária).
Juan Juan
Observe que, se você obtiver FOO<newline>BAR, não saberá se é uma FOO<newline>BARvariável de ambiente (que export -pnão seria exibida com a maioria dos shells, consulte env $'FOO\nBAR=test' awk 'BEGIN{for (v in ENVIRON) print v}') ou se é uma variável de ambiente FOOe BAR.
Stéphane Chazelas
Note-se que GNU awks variáveis de ambiente conjuntos de seu próprio ( AWKPATHe AWKLIBPATHno meu sistema)
Stéphane Chazelas
@ StéphaneChazelas - re: nova linha incorporada no nome var - concordou - difícil de defender contra isso com o código do shell. Re: AWKPATH & AWKLIBPATH poluição, notei que inserção insidiosa também. Isso é gnu awk, não bsd awk.
Juan
0

Eu gosto de coisas simples; isso funcionará para sistemas POSIX:

printenv | sed 's;=.*;;' | sort
HOME
HOSTNAME
PATH
PWD
SHLVL
TERM
todd_dsm
fonte
5
export AAA=$'multi\nBBB=line'
roaima 26/09/19
@todd_dsm - Isso falha nas variáveis ​​de ambiente que possuem valores que abrangem mais de uma linha (por exemplo, às vezes TERMCAP - vejo isso quando em uma sessão da tela (1), IIRC). Portanto, esta resposta não atende aos requisitos descritos na pergunta original. Eu também gosto de simples, mas isso geralmente não funciona.
Juan
O boato que você editou para fora em seu post original foi interessante para a festança: compgen -e. Isso não ajuda no meu script portátil (por exemplo, quando o bash não está disponível), mas é interessante.
Juan Juan
só por curiosidade, por que se restringir à concha de bourne (posix)? ser compatível com posix é ótimo, mas você perde muita funcionalidade nessa busca. você pode ser portátil e NÃO compatível com posix com o bash; faz parte da família GNU.
todd_dsm
Usando dashno debian, eu obtenho os mesmos resultados com o comando acima ou modificado printenv | sed 's;*=.;;' | sortpara obter os valores. Eu exportei a variável yoe atribuí o seu primeiro comentário acima; impresso como esperado, com várias linhas. não tenho certeza do que está experimentando, mas não deve haver saída truncada. execute o comando no shell; o que quer que ele produz, há como deve funcionar; não espere truncamento. Então, dentro do contexto de TERMCAP / screen / iirc; deve ser o mesmo. Se a saída não corresponder, é provável que haja um problema com um desses programas.
todd_dsm