web-dev-qa-db-fra.com

Comment lister les variables déclarées dans le script en bash?

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
84
lauriys

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 :-))

137
Douglas Leeder
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 .

38
Juven Xu
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
9
akostadinov

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) 
4
Cesar Roque

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
3
ezpz

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 settoujours 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 ...

1
Stevel

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"
    } 
0
Yordan Georgiev

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
0
Chen Levy

La commande printenv:

printenv imprime tout environment variables ainsi que leurs valeurs.

Bonne chance...

0
Akash

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.

0
Dejay Clayton