Risposte:
set
produrrà le variabili, sfortunatamente produrrà anche le definizioni delle funzioni.
Fortunatamente la modalità POSIX emette solo le variabili:
( set -o posix ; set ) | less
Piping less
o reindirizzamento a dove desideri le opzioni.
Quindi, per ottenere le variabili dichiarate solo nello 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
(O almeno qualcosa basato su quello :-))
VARS="`set -o posix ; set`"; source script; SCRIPT_VARS="`grep -vFe "$VARS" <<<"$(set -o posix ; set)" | grep -v ^VARS=`"; unset VARS;
. Questo produrrà anche le variabili in un formato pronto per il salvataggio. L'elenco includerà le variabili modificate dallo script (dipende se ciò è desiderabile)
source
, dovresti essere in grado di farlo con l'output di declare -p
.
before=$(set -o posix; set); dosomestuff; diff <(echo "$before") <(set -o posix; set)
compgen -v
Elenca tutte le variabili comprese quelle locali. L'ho imparato da Ottieni elenco di variabili il cui nome corrisponde a un determinato modello e l'ho usato nel mio script .
compgen -v
elenca anche le variabili globali non impostate localmente. Non sono sicuro che sia un bug di vecchia data o il comportamento desiderato.
for i in _ {a..z} {A..Z}; do eval "echo \${!$i@}" ; done | xargs printf "%s\n"
Questo deve stampare tutti i nomi delle variabili di shell. Puoi ottenere un elenco prima e dopo il sourcing del tuo file proprio come con "set" a diff quali variabili sono nuove (come spiegato nelle altre risposte). Ma tieni presente che questo filtro con diff può filtrare alcune variabili di cui hai bisogno ma che erano presenti prima di acquisire il tuo file.
Nel tuo caso, se sai che i nomi delle tue variabili iniziano con "VARIABILE", puoi procurarti lo script e fare:
for var in ${!VARIABLE@}; do
printf "%s%q\n" "$var=" "${!var}"
done
AGGIORNAMENTO: Per la pura soluzione BASH (nessun comando esterno utilizzato):
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})"
Sulla base di alcune delle risposte precedenti, questo ha funzionato per me:
before=$(set -o posix; set | sort);
file sorgente :
comm -13 <(printf %s "$before") <(set -o posix; set | sort | uniq)
Se puoi post-processare, (come già accennato) potresti semplicemente effettuare una set
chiamata all'inizio e alla fine del tuo script (ciascuno su un file diverso) e fare una differenza sui due file. Renditi conto che questo conterrà ancora del rumore.
Puoi anche farlo in modo programmatico. Per limitare l'output solo all'ambito corrente, è necessario implementare un wrapper per la creazione di variabili. Per esempio
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
Che produce
VAR1=abc
VAR2=bcd
VAR3=cde
Ecco qualcosa di simile alla risposta @GinkgoFr, ma senza i problemi identificati da @Tino o @DejayClayton, ed è più robusto del set -o posix
bit intelligente di @ DouglasLeeder :
+ function SOLUTION() { (set +o posix; set) | sed -ne '/^\w\+=/!q; p;'; }
La differenza è che questa soluzione si FERMA dopo il primo report non variabile, ad esempio la prima funzione riportata da set
BTW: Il problema "Tino" è risolto. Anche se POSIX è disattivato e le funzioni sono riportate da set
, la sed ...
parte della soluzione consente solo il passaggio di rapporti variabili (ad esempio VAR=VALUE
righe). In particolare, la A2
fa non spurio rendono nell'uscita.
+ function a() { echo $'\nA2=B'; }; A0=000; A9=999;
+ SOLUTION | grep '^A[0-9]='
A0=000
A9=999
AND: Il problema "DejayClayton" è stato risolto (le nuove righe incorporate nei valori delle variabili non interrompono l'output - ognuna VAR=VALUE
riceve una singola riga di output):
+ A1=$'111\nA2=222'; A0=000; A9=999;
+ SOLUTION | grep '^A[0-9]='
A0=000
A1=$'111\nA2=222'
A9=999
NOTA: la soluzione fornita da @DouglasLeeder soffre del problema "DejayClayton" (valori con newline incorporati). Di seguito, il A1
è sbagliato e A2
non dovrebbe essere visualizzato affatto.
$ 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: Non credo che la versione delle bash
cose, ma potrebbe. Ho fatto i miei test / sviluppo su questo:
$ bash --version
GNU bash, version 4.4.12(1)-release (x86_64-pc-msys)
POST-SCRIPT: date alcune delle altre risposte all'OP, sono rimasto <100% sicuro che converte set
sempre le nuove righe all'interno del valore in \n
cui si basa questa soluzione per evitare il problema "DejayClayton". Forse è un comportamento moderno? O una variazione in fase di compilazione? O un'opzione set -o
o shopt
un'impostazione? Se sei a conoscenza di tali variazioni, aggiungi un commento ...
Dal punto di vista della sicurezza, sia di @ akostadinov risposta o di @ JuvenXu risposta è preferibile far valere l'uscita non strutturato del set
comando, per il seguente potenziale problema di sicurezza:
#!/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
La funzione sopra doLogic
utilizza set
per verificare la presenza di variabili PS1
per determinare se lo script è interattivo o meno (non importa se questo è il modo migliore per raggiungere tale obiettivo; questo è solo un esempio).
Tuttavia, l'output di set
non è strutturato, il che significa che qualsiasi variabile che contiene una nuova riga può contaminare totalmente i risultati.
Questo, ovviamente, è un potenziale rischio per la sicurezza. Utilizzare invece il supporto di Bash per l'espansione indiretta del nome di variabile o compgen -v
.
Prova questo: set | egrep "^\w+="
(con o senza | less
tubazioni)
La prima soluzione proposta,, ( set -o posix ; set ) | less
funziona ma ha un inconveniente: trasmette i codici di controllo al terminale, quindi non vengono visualizzati correttamente. Quindi, ad esempio, se c'è (probabilmente) una IFS=$' \t\n'
variabile, possiamo vedere:
IFS='
'
…anziché.
La mia egrep
soluzione mostra questo (ed eventualmente altri simili) correttamente.
bash -c $'a() { echo "\nA=B"; }; unset A; set | egrep "^\w+="' | grep ^A
visualizzazioni semplicemente sbagliateA=B"
-> Fail!
Probabilmente ho rubato la risposta tempo fa ... comunque leggermente diversa come funzione:
##
# 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"
}
Un modo semplice per farlo è usare la modalità rigorosa bash impostando le variabili d'ambiente di sistema prima di eseguire lo script e usare diff per ordinare solo quelle del tuo 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
Ora puoi recuperare le variabili del tuo script in /tmp/script_vars.log. O almeno qualcosa basato su quello!
Un po 'tardi per la festa, ma ecco un altro suggerimento:
#!/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'
La riga di comando diff + sed pipeline restituisce tutte le variabili definite dallo script nel formato desiderato (come specificato nel post dell'OP):
VARIABLE1=a
VARIABLE2=b
VARIABLE3=c
-o posix
ora un diff conterrà solo le variabili.