it-swarm-pt.tech

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

O comando bash builtin set, se chamado sem argumentos, imprimirá todas as variáveis ​​de ambiente e de shell, 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 com que o comando bash builtin set imprima apenas as variáveis ​​e não as funções?

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

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

59
lesmana

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

No man bash, na seção Shell BUILTIN COMMANDS (na seção set), diz: "No modo posix, apenas as variáveis ​​do Shell são listadas."

(set -o posix; set)

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

set -o posix; set; set +o posix
54
temp

Aqui estão algumas soluções alternativas:

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

demolir:

  1. declare imprime todas as variáveis ​​definidas (exportadas ou não) e funções.
  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 imprimirá apenas 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 ... cut:

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

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

comparar:

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

Isso torna bastante difícil usar essa 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 embutido compgen foi criado para ser usado em scripts de conclusão. Para este fim, compgen -v lista todas as variáveis ​​definidas. A desvantagem: lista apenas os nomes das variáveis, não os valores.

Aqui está um hack para listar também os valores.

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

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

32
lesmana

O typeset embutido 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 as novas linhas nos valores dos 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 apenas 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").

Observe também que isso pressupõe que não há variável de ambiente com um nome que não corresponda às restrições do bash nos nomes de 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
13

Não tenho certeza de como alguém pode 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 seguidas 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 título sugere, você deseja subtrair desta lista as variáveis ​​que são exportadas e, assim, obter uma lista de variáveis ​​não exportadas, poderá fazer algo assim

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

Para resumir um pouco, aqui está o que ele faz:

  1. set | grep "^\([[:alnum:]]\|[[:punct:]]\)\+=" | sort > ./setvars: Espera-se que todas as variáveis ​​(como discutidas anteriormente) sejam obtidas, as classifique e cole o resultado em um arquivo.
  2. && env | sort: Após a conclusão do comando anterior, chamaremos env e classificaremos sua saída.
  3. | comm -23 ./setvars -: Finalmente, canalizamos 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 para nossa saída do conjunto.

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

7
Steven D

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

6
unxnut

Experimente o comando printenv:

$printenv
2
Emilio R.

No bash, isso imprimirá apenas nomes de variáveis:

compgen -v

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

declare -p
1
Isaac

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

Aqui está a técnica que eu tenho usado para armazenar o estado da função em um arquivo para que eu possa continuar mais tarde. O primeiro produz um despejo 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 funcionam despejando linhas até encontrar um sem um caractere '=', o que ocorre quando a primeira função é listada. O último corta a tarefa.

0
Wil

diferindo de um Shell limpo para garantir também que vários dos 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

0
untore