Dans mon script en bash, il y a beaucoup de variables, et je dois faire quelque chose pour les enregistrer dans un fichier. Ma question est de savoir comment répertorier toutes les variables déclarées dans mon script et obtenir une liste comme celle-ci:
VARIABLE1=abc
VARIABLE2=def
VARIABLE3=ghi
set
affichera les variables, malheureusement il affichera également les fonctions définies.
Heureusement, le mode POSIX ne produit que les variables:
( set -o posix ; set ) | less
Tuyauterie vers less
, ou redirigez vers où vous voulez les options.
Donc, pour obtenir les variables déclarées dans le script uniquement:
( 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 au moins quelque chose basé sur cela :-))
compgen -v
Il répertorie toutes les variables, y compris les variables locales. Je l'ai appris de Obtenir la liste des variables dont le nom correspond à un certain modèle , et je l'ai utilisé dans mon script .
for i in _ {a..z} {A..Z}; do eval "echo \${!$i@}" ; done | xargs printf "%s\n"
Cela doit afficher tous les noms de variables Shell. Vous pouvez obtenir une liste avant et après le sourcing de votre fichier, tout comme avec "set" pour différencier les nouvelles variables (comme expliqué dans les autres réponses). Mais gardez à l'esprit qu'un tel filtrage avec diff peut filtrer certaines variables dont vous avez besoin mais qui étaient présentes avant de sourcer votre fichier.
Dans votre cas, si vous savez que les noms de vos variables commencent par "VARIABLE", alors vous pouvez source votre script et faire:
for var in ${!VARIABLE@}; do
printf "%s%q\n" "$var=" "${!var}"
done
PDATE: Pour une solution BASH pure (aucune commande externe utilisée):
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
Sur la base de certaines des réponses ci-dessus, cela a fonctionné pour moi:
before=$(set -o posix; set | sort);
fichier source:
comm -13 <(printf %s "$before") <(set -o posix; set | sort | uniq)
Si vous pouvez post-traiter (comme déjà mentionné), vous pouvez simplement placer un appel set
au début et à la fin de votre script (chacun vers un fichier différent) et faire une différence sur les deux fichiers. Sachez que cela contiendra toujours du bruit.
Vous pouvez également le faire par programme. Pour limiter la sortie à votre portée actuelle, vous devez implémenter un wrapper pour la création de variables. Par exemple
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
Qui donne
VAR1=abc
VAR2=bcd
VAR3=cde
Voici quelque chose de similaire à la réponse @GinkgoFr, mais sans les problèmes identifiés par @Tino ou @DejayClayton, et est plus robuste que l'intelligent _ de DouglasLeeder set -o posix
bit:
+ function SOLUTION() { (set +o posix; set) | sed -ne '/^\w\+=/!q; p;'; }
La différence est que cette solution ARRÊTE après le premier rapport non variable, par ex. la première fonction rapportée par set
BTW: Le problème "Tino" est résolu. Même si POSIX est désactivé et que les fonctions sont signalées par set
, le sed ...
la partie de la solution n'autorise que les rapports variables (par exemple VAR=VALUE
lignes). En particulier, le A2
ne pas transforme faussement en sortie.
+ function a() { echo $'\nA2=B'; }; A0=000; A9=999;
+ SOLUTION | grep '^A[0-9]='
A0=000
A9=999
ET: Le problème "DejayClayton" est résolu (les sauts de ligne intégrés dans les valeurs variables pas perturbent la sortie - chaque VAR=VALUE
obtenir une seule ligne de sortie):
+ A1=$'111\nA2=222'; A0=000; A9=999;
+ SOLUTION | grep '^A[0-9]='
A0=000
A1=$'111\nA2=222'
A9=999
REMARQUE: La solution fournie par @DouglasLeeder souffre du problème "DejayClayton" (valeurs avec des retours à la ligne intégrés). Sous le A1
est faux et A2
ne devrait pas s'afficher du tout.
$ A1=$'111\nA2=222'; A0=000; A9=999; (set -o posix; set) | grep '^A[0-9]='
A0=000
A1='111
A2=222'
A9=999
ENFIN: Je ne pense pas que la version de bash
soit importante, mais cela pourrait. J'ai fait mes tests/développement sur celui-ci:
$ bash --version
GNU bash, version 4.4.12(1)-release (x86_64-pc-msys)
POST-SCRIPT: Étant donné certaines des autres réponses à l'OP, je suis <100% sûr que set
toujours convertit les sauts de ligne dans la valeur en \n
, sur lequel cette solution s'appuie pour éviter le problème "DejayClayton". C'est peut-être un comportement moderne? Ou une variation au moment de la compilation? Ou un set -o
ou shopt
réglage de l'option? Si vous connaissez de telles variations, veuillez ajouter un commentaire ...
J'ai probablement volé la réponse tout à l'heure ... de toute façon légèrement différent comme func:
##
# 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"
}
Essayez d'utiliser un script (appelons-le "ls_vars"):
#!/bin/bash
set -a
env > /tmp/a
source $1
env > /tmp/b
diff /tmp/{a,b} | sed -ne 's/^> //p'
chmod + x it, et:
ls_vars your-script.sh > vars.files.save
printenv
:printenv
imprime tout environment variables
ainsi que leurs valeurs.
Bonne chance...
Du point de vue de la sécurité, @ akostadinov answer ou @ JuvenXu answer est préférable à la sortie non structurée de la commande set
, en raison du potentiel suivant faille de sécurité:
#!/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 fonction ci-dessus doLogic
utilise set
pour vérifier la présence de la variable PS1
pour déterminer si le script est interactif ou non (peu importe si c'est la meilleure façon d'atteindre cet objectif; ce n'est qu'un exemple.)
Cependant, la sortie de set
n'est pas structurée, ce qui signifie que toute variable qui contient une nouvelle ligne peut contaminer totalement les résultats.
Il s'agit bien sûr d'un risque potentiel pour la sécurité. Utilisez plutôt la prise en charge de Bash pour l'expansion indirecte du nom de variable ou compgen -v
.