Respostas:
set
irá exibir as variáveis, infelizmente também irá exibir as funções definidas também.
Felizmente, o modo POSIX exibe apenas as variáveis:
( set -o posix ; set ) | less
Canalizando less
ou redirecionando para onde você deseja as opções.
Portanto, para obter as variáveis declaradas apenas no script:
( set -o posix ; set ) >/tmp/variables.before
source script
( set -o posix ; set ) >/tmp/variables.after
diff /tmp/variables.before /tmp/variables.after
rm /tmp/variables.before /tmp/variables.after
(Ou pelo menos algo baseado nisso :-))
VARS="`set -o posix ; set`"; source script; SCRIPT_VARS="`grep -vFe "$VARS" <<<"$(set -o posix ; set)" | grep -v ^VARS=`"; unset VARS;
. Isso também produzirá os vars em um formato pronto para salvar. A lista incluirá as variáveis que o script alterou (depende se isso é desejável)
source
, deve ser capaz de fazê-lo com a saída de declare -p
.
before=$(set -o posix; set); dosomestuff; diff <(echo "$before") <(set -o posix; set)
compgen -v
Ele lista todas as variáveis, incluindo as locais. Aprendi isso em Get list of variables cujo nome corresponde a um determinado padrão e usei-o em meu script .
compgen -v
lista também variáveis globais que não foram definidas localmente. Não tenho certeza se esse é um bug antigo ou o comportamento desejado.
for i in _ {a..z} {A..Z}; do eval "echo \${!$i@}" ; done | xargs printf "%s\n"
Isso deve imprimir todos os nomes de variáveis do shell. Você pode obter uma lista antes e depois de fornecer seu arquivo como em "set" para diff quais variáveis são novas (como explicado nas outras respostas). Mas tenha em mente que essa filtragem com diff pode filtrar algumas variáveis que você precisa, mas que estavam presentes antes de fornecer seu arquivo.
No seu caso, se você sabe que os nomes das variáveis começam com "VARIÁVEL", você pode originar seu script e fazer:
for var in ${!VARIABLE@}; do
printf "%s%q\n" "$var=" "${!var}"
done
ATUALIZAÇÃO: Para solução BASH pura (sem comandos externos usados):
for i in _ {a..z} {A..Z}; do
for var in `eval echo "\\${!$i@}"`; do
echo $var
# you can test if $var matches some criteria and put it in the file or ignore
done
done
eval "printf '%q\n' $(printf ' "${!%s@}"' _ {a..z} {A..Z})"
Com base em algumas das respostas acima, isso funcionou para mim:
before=$(set -o posix; set | sort);
arquivo fonte :
comm -13 <(printf %s "$before") <(set -o posix; set | sort | uniq)
Se você pode pós-processar, (como já mencionado) você pode apenas fazer uma set
chamada no início e no final do seu script (cada um para um arquivo diferente) e fazer uma comparação entre os dois arquivos. Perceba que isso ainda conterá algum ruído.
Você também pode fazer isso programaticamente. Para limitar a saída apenas ao seu escopo atual, você teria que implementar um wrapper para a criação de variáveis. Por exemplo
store() {
export ${1}="${*:2}"
[[ ${STORED} =~ "(^| )${1}($| )" ]] || STORED="${STORED} ${1}"
}
store VAR1 abc
store VAR2 bcd
store VAR3 cde
for i in ${STORED}; do
echo "${i}=${!i}"
done
Que rende
VAR1=abc
VAR2=bcd
VAR3=cde
Aqui está algo semelhante à resposta de @GinkgoFr, mas sem os problemas identificados por @Tino ou @DejayClayton, e é mais robusto do que a parte inteligente de @ DouglasLeeder set -o posix
:
+ function SOLUTION() { (set +o posix; set) | sed -ne '/^\w\+=/!q; p;'; }
A diferença é que esta solução PARA após o primeiro relatório não variável, por exemplo, a primeira função relatada por set
BTW: O problema "Tino" está resolvido. Mesmo que POSIX esteja desligado e as funções sejam relatadas por set
, a sed ...
parte da solução permite apenas relatórios de variáveis (por exemplo, VAR=VALUE
linhas). Em particular, o A2
que não spuriously fazê-lo na saída.
+ function a() { echo $'\nA2=B'; }; A0=000; A9=999;
+ SOLUTION | grep '^A[0-9]='
A0=000
A9=999
AND: O problema "DejayClayton" foi resolvido (novas linhas incorporadas em valores de variáveis não interrompem a saída - cada VAR=VALUE
uma obtém uma única linha de saída):
+ A1=$'111\nA2=222'; A0=000; A9=999;
+ SOLUTION | grep '^A[0-9]='
A0=000
A1=$'111\nA2=222'
A9=999
NOTA: A solução fornecida por @DouglasLeeder sofre do problema "DejayClayton" (valores com novas linhas embutidas). Abaixo deA1
está errado e A2
não deve ser exibido.
$ A1=$'111\nA2=222'; A0=000; A9=999; (set -o posix; set) | grep '^A[0-9]='
A0=000
A1='111
A2=222'
A9=999
FINALMENTE: Eu não acho que a versão de bash
importe, mas pode. Eu fiz meu teste / desenvolvimento neste:
$ bash --version
GNU bash, version 4.4.12(1)-release (x86_64-pc-msys)
PÓS-SCRIPT: dadas algumas das outras respostas ao OP, tenho <100% de certeza de que set
sempre converte novas linhas dentro do valor para \n
, no qual essa solução depende para evitar o problema "DejayClayton". Talvez seja um comportamento moderno? Ou uma variação em tempo de compilação? Ou uma configuração de opção set -o
ou shopt
? Se você souber de tais variações, por favor, adicione um comentário ...
A partir de uma perspectiva de segurança, quer de @ akostadinov resposta ou de @ JuvenXu resposta é preferível confiando na saída desestruturado do set
comando, devido ao seguinte potencial falha de segurança:
#!/bin/bash
function doLogic()
{
local COMMAND="${1}"
if ( set -o posix; set | grep -q '^PS1=' )
then
echo 'Script is interactive'
else
echo 'Script is NOT interactive'
fi
}
doLogic 'hello' # Script is NOT interactive
doLogic $'\nPS1=' # Script is interactive
A função acima doLogic
usa set
para verificar a presença de variável PS1
para determinar se o script é interativo ou não (não importa se esta é a melhor maneira de atingir esse objetivo; este é apenas um exemplo).
No entanto, a saída de set
não é estruturada, o que significa que qualquer variável que contenha uma nova linha pode contaminar totalmente os resultados.
Isso, é claro, é um risco potencial à segurança. Em vez disso, use o suporte do Bash para expansão de nome de variável indireta ou compgen -v
.
Experimente o seguinte: set | egrep "^\w+="
(com ou sem o| less
tubulação)
A primeira solução proposta,, ( set -o posix ; set ) | less
funciona, mas tem uma desvantagem: ela transmite códigos de controle para o terminal, de modo que eles não são exibidos corretamente. Então, por exemplo, se houver (provavelmente) uma IFS=$' \t\n'
variável, podemos ver:
IFS='
'
…em vez de.
Minha egrep
solução exibe isso (e eventualmente outros semelhantes) corretamente.
bash -c $'a() { echo "\nA=B"; }; unset A; set | egrep "^\w+="' | grep ^A
exibições erradasA=B"
-> Falha!
Provavelmente roubei a resposta há algum tempo ... de qualquer maneira, um pouco diferente em função:
##
# usage source bin/nps-bash-util-funcs
# doEchoVars
doEchoVars(){
# if the tmp dir does not exist
test -z ${tmp_dir} && \
export tmp_dir="$(cd "$(dirname $0)/../../.."; pwd)""/dat/log/.tmp.$$" && \
mkdir -p "$tmp_dir" && \
( set -o posix ; set )| sort >"$tmp_dir/.vars.before"
( set -o posix ; set ) | sort >"$tmp_dir/.vars.after"
cmd="$(comm -3 $tmp_dir/.vars.before $tmp_dir/.vars.after | perl -ne 's#\s+##g;print "\n $_ "' )"
echo -e "$cmd"
}
Uma maneira simples de fazer isso é usar o modo estrito bash definindo as variáveis de ambiente do sistema antes de executar seu script e usar diff para classificar apenas as do seu script:
# Add this line at the top of your script :
set > /tmp/old_vars.log
# Add this line at the end of your script :
set > /tmp/new_vars.log
# Alternatively you can remove unwanted variables with grep (e.g., passwords) :
set | grep -v "PASSWORD1=\|PASSWORD2=\|PASSWORD3=" > /tmp/new_vars.log
# Now you can compare to sort variables of your script :
diff /tmp/old_vars.log /tmp/new_vars.log | grep "^>" > /tmp/script_vars.log
Agora você pode recuperar variáveis de seu script em /tmp/script_vars.log. Ou pelo menos algo baseado nisso!
Um pouco tarde para a festa, mas aqui vai outra sugestão:
#!/bin/bash
set_before=$( set -o posix; set | sed -e '/^_=*/d' )
# create/set some variables
VARIABLE1=a
VARIABLE2=b
VARIABLE3=c
set_after=$( set -o posix; unset set_before; set | sed -e '/^_=/d' )
diff <(echo "$set_before") <(echo "$set_after") | sed -e 's/^> //' -e '/^[[:digit:]].*/d'
A linha de comando do pipeline diff + sed exibe todas as variáveis definidas pelo script no formato desejado (conforme especificado na postagem do OP):
VARIABLE1=a
VARIABLE2=b
VARIABLE3=c
-o posix
agora, um diff conterá apenas as variáveis.