Como imprimir apenas variáveis definidas (variáveis de shell e / ou ambiente) no bash

49

O comando bash builtin set , se invocado sem argumentos, imprimirá todas as variáveis de shell e ambiente, mas também todas as funções definidas. Isso torna a saída inutilizável para humanos e difícil de grep .

Como posso fazer o comando bash builtin set imprimir apenas as variáveis e não as funções?

Existem outros comandos que imprimem somente as variáveis do shell, sem as funções?

Nota: o bash diferencia entre variáveis de shell e variáveis de ambiente. veja aqui Diferença entre variáveis de ambiente e variáveis de ambiente exportadas no bash

    
por lesmana 26.10.2010 / 00:33

9 respostas

46

"Existem outros comandos que imprimem apenas as variáveis do shell, sem as funções?"

No homem bash, na seção SHELL BUILTIN COMMANDS (na seção set) ele diz: "No modo posix, apenas as variáveis do shell são listadas."

(set -o posix; set)

nota: a sintaxe () gera um subshell, se você não gosta de usar o forking, use a versão mais detalhada

set -o posix; set; set +o posix
    
por 04.03.2014 / 10:03
30

Aqui estão algumas soluções alternativas:

$ comm -3 <(declare | sort) <(declare -f | sort)

quebra:

  1. declare imprime todas as variáveis definidas (exportadas ou não) e função.
  2. declare -f imprime apenas funções.
  3. comm -3 removerá todas as linhas comuns a ambos. Com efeito, isso removerá as funções, deixando apenas as variáveis.

Para imprimir apenas variáveis que não são exportadas:

$ comm -3 <(comm -3 <(declare | sort) <(declare -f | sort)) <(env | sort)

Outra solução alternativa:

$ declare -p

Isso só imprimirá as variáveis, mas com alguns atributos feios.

declare -- BASH="/bin/bash"
declare -ir BASHPID=""
declare -A BASH_ALIASES='()'
declare -a BASH_ARGC='()'
...

Você pode cortar os atributos usando ... cortar:

$ declare -p | cut -d " " -f 3

Uma desvantagem é que o valor do IFS é interpretado em vez de exibido.

compare:

$ comm -3 <(declare | sort) <(declare -f | sort)
...
IFS=$' \t\n'
...
$ declare -p | cut -d " " -f 3
...
IFS="
"
...

Isso dificulta bastante o uso dessa saída para processamento adicional, por causa desse único " em uma linha. Talvez algum IFS-fu possa ser feito para evitar isso.

Ainda outra solução alternativa, usando compgen :

$ compgen -v

O bash builtin compgen foi criado para ser usado em scripts de conclusão. Para este fim, compgen -v lista todas as variáveis definidas. O lado negativo: lista apenas os nomes das variáveis, não os valores.

Aqui está um hack para listar os valores.

$ compgen -v | while read var; do printf "%s=%q\n" "$var" "${!var}"; done

A vantagem: é uma solução bash pura. A desvantagem: alguns valores são confusos devido à interpretação através de printf . Além disso, o subshell do pipe e / ou do loop adiciona algumas variáveis extras.

    
por 11.01.2011 / 16:13
13

O typeset builtin estranhamente tem uma opção para mostrar apenas funções ( -f ), mas não para mostrar apenas parâmetros. Felizmente, typeset (ou set ) exibe todos os parâmetros antes que todas as funções, funções e nomes de parâmetros não possam conter novas linhas ou sinais de igual e novas linhas em valores de parâmetros sejam citadas (elas aparecem como \n ). Então você pode parar na primeira linha que não contém um sinal de igual:

set | awk -F '=' '! /^[0-9A-Z_a-z]+=/ {exit} {print $1}'

Isso só imprime os nomes dos parâmetros; Se você quiser os valores, altere print $1 para print $0 .

Observe que isso imprime todos os nomes de parâmetros (parâmetros e variáveis são usados como sinônimos aqui), não apenas variáveis de ambiente ("variável de ambiente" é sinônimo de "parâmetros exportados").

Note também que isto assume que não existe uma variável de ambiente com um nome que não corresponda às restrições do bash nos nomes dos parâmetros. Tais variáveis não podem ser criadas dentro do bash, mas podem ter sido herdadas do ambiente quando o bash é iniciado:

env 'foo ()
{
  =oops' bash
    
por 26.10.2010 / 20:58
7

Não tenho certeza de como é possível fazer com que set imprima apenas variáveis. No entanto, olhando para a saída de set , consegui criar o seguinte que parece pegar apenas variáveis:

$ set | grep "^\([[:alnum:]]\|[[:punct:]]\)\+=" 

Basicamente, estou procurando linhas que começam com letras, números ou pontuação seguidos por um "=". Da saída que eu vi, isso pega todas as variáveis; no entanto, duvido que isso seja muito portátil.

Se, como o seu título sugere, você quiser subtrair desta lista as variáveis que são exportadas e, assim, obter uma lista de variáveis não exportadas, então você poderia fazer algo parecido com isto

$ set | grep "^\([[:alnum:]]\|[[:punct:]]\)\+=" | sort > ./setvars && env | sort | comm -23 ./setvars - 

Para detalhar um pouco, veja o que ele faz:

  1. set | grep "^\([[:alnum:]]\|[[:punct:]]\)\+=" | sort > ./setvars : Isso toma todas as variáveis (como discutido anteriormente), classifica-as e cola o resultado em um arquivo.
  2. && env | sort : Depois que o comando anterior estiver completo, chamaremos env e classificaremos sua saída.
  3. | comm -23 ./setvars - : Por fim, enviamos a saída classificada de env para comm e usamos a opção -23 para imprimir as linhas exclusivas do primeiro argumento, neste caso as linhas exclusivas de nossa saída do conjunto.

Quando terminar, talvez você queira limpar o arquivo temporário criado com o comando rm ./setvars

    
por 26.10.2010 / 05:59
5

Basta usar o comando env . Não imprime funções.

    
por 04.06.2013 / 16:48
2

Experimente o comando printenv:

$printenv
    
por 04.06.2013 / 16:23
1

No bash, isso imprimirá apenas os nomes das variáveis:

compgen -v

Ou, se os valores também forem necessários, use:

declare -p
    
por 23.04.2018 / 06:42
0

difere contra um shell limpo para garantir que também vars de scripts rc sejam deixados de fora

## get mostly local vars
diff_env(){
    diff <(bash -cl 'set -o posix && set') \
        <(set -o posix && set && set +o posix) | \
        grep -E "^>|^\+" | \
        grep -Ev "^(>|\+|\+\+) ?(BASH|COLUMNS|LINES|HIST|PPID|SHLVL|PS(1|2)|SHELL|FUNC)" | \
        sed -r 's/^> ?|^\+ ?//'
}

a versão com comm seria muito complicada

    
por 09.06.2017 / 13:04
0

A resposta aceita é ótima. Eu estou oferecendo uma alternativa que não envolve a configuração do modo POSIX:

Aqui está a técnica que tenho usado para armazenar o estado da função em um arquivo para que eu possa continuar depois. O primeiro produz um dump de estado e o segundo produz apenas uma lista dos nomes das variáveis.

set 2>/dev/null | while read a; do [[ $a == *=* ]] || break; echo $a; done 

set 2>/dev/null | while read a; do [[ $a == *=* ]] || break; echo ${a/=*}; done 

Ambos trabalham por linhas de despejo até encontrar um sem um caractere '=', que ocorre quando a primeira função é listada. Este último corta a atribuição.

    
por 28.11.2017 / 19:38