2009-08-20 9 views
57

In meinem Skript in bash gibt es viele Variablen, und ich muss etwas machen, um sie in Datei zu speichern. Meine Frage ist, wie alle Variablen in meinem Skript deklariert Liste und die Liste wie diese:Wie listet man in bash deklarierte Variablen auf?

VARIABLE1=abc 
VARIABLE2=def 
VARIABLE3=ghi 

Antwort

102

set ausgeben wird, die Variablen, leider wird es auch die Ausgabe definiert die Funktionen als auch.

Zum Glück POSIX-Modus gibt nur die Variablen:

(set -o posix ; set) | less 

Piping zu less oder umleiten, wo Sie die Optionen möchten.

So sind die Variablen in nur das Skript deklariert werden:

(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 

(Oder zumindest etwas auf der Grundlage dieses :-))

+0

Sie bearbeitet, während ich posten. Netter Aufruf mit dem '-o posix' jetzt wird ein Diff nur die Variablen enthalten. – ezpz

+6

Ohne temporäre Dateien zu verwenden: 'VARS =" \ 'set -o posix; set \" "; Quellskript; SCRIPT_VARS = "\' grep -vFe "$ VARS" <<< "$ (setze -o posix; setze)" | grep -v^VARS = \ ""; unset VARS; '. Dies wird auch die vars in einem ready-to-save-Format ausgeben. Die Liste enthält die Variablen, die das Skript geändert hat (es hängt davon ab, ob dies wünschenswert ist) –

+0

Leider gibt der Posix-Modus auch Vars aus, die nicht gesetzt werden können, so dass Sie die Ausgabe nicht "auslesen" und alle wieder einlesen können. –

3

Wenn Sie nachbearbeiten kann, (wie bereits erwähnt) Sie können einfach einen set Aufruf am Anfang und Ende Ihres Skripts (jeweils in eine andere Datei) platzieren und einen Vergleich der beiden Dateien durchführen. Erkenne, dass dies immer noch etwas Rauschen enthalten wird.

Sie können dies auch programmatisch tun. Um die Ausgabe auf den aktuellen Bereich zu beschränken, müssten Sie einen Wrapper für die Variablenerstellung implementieren. Zum Beispiel

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 

Welche

VAR1=abc 
VAR2=bcd 
VAR3=cde 
0

Versuchen Sie ein Skript (nennen wir es "ls_vars") ergibt:

#!/bin/bash 
    set -a 
    env > /tmp/a 
    source $1 
    env > /tmp/b 
    diff /tmp/{a,b} | sed -ne 's/^> //p' 

chmod + x es, und:

ls_vars your-script.sh > vars.files.save 
+2

Dies zeigt keine lokalen Variablen, nur exportierte. –

8
for i in _ {a..z} {A..Z}; do eval "echo \${[email protected]}" ; done | xargs printf "%s\n" 

Dies muss alle Shell-Variablennamen drucken. Sie können eine Liste vor und nach dem Sourcing Ihrer Datei erhalten, genau wie bei "set", um diff zu bestimmen, welche Variablen neu sind (wie in den anderen Antworten erklärt). Bedenken Sie jedoch, dass eine solche Filterung mit diff einige Variablen herausfiltern kann, die Sie benötigen, die aber vor dem Auffinden Ihrer Datei vorhanden waren.

In Ihrem Fall, wenn Sie Ihre Variablen Namen kennen beginnen mit ‚Variable‘, dann können Sie Ihr Skript beziehen und zu tun:

for var in ${[email protected]}; do 
    printf "%s%q\n" "$var=" "${!var}" 
done 

UPDATE: Für reine BASH-Lösung (keine externen Kommandos):

for i in _ {a..z} {A..Z}; do 
    for var in `eval echo "\\${[email protected]}"`; do 
     echo $var 
     # you can test if $var matches some criteria and put it in the file or ignore 
    done 
done 
0

Aus sicherheitstechnischer Sicht entweder @ akostadinov des answer oder @answer des JuvenXu ist bevorzugt auf dem unstrukturierten Ausgang des set Befehls, aufgrund der folgenden potenziellen Sicherheitslücke unter Berufung:

#!/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 

Die obige Funktion doLogic Anwendungen set für das Vorhandensein von variablen PS1 zu überprüfen, um festzustellen, ob das Skript interaktiv ist oder nicht (egal, ob dies der beste Weg ist, um dieses Ziel zu erreichen, dies ist nur ein Beispiel.)

Die Ausgabe von set ist jedoch unstrukturiert, was bedeutet, dass jede Variable, die eine Newline enthält, die Ergebnisse vollständig verschmutzen kann.

Dies ist natürlich ein potenzielles Sicherheitsrisiko. Verwenden Sie stattdessen entweder Bashs Unterstützung für die Erweiterung indirekter Variablennamen oder compgen -v.

-1

Try this: set | egrep "^\w+=" (mit oder ohne | less Verrohrung)

Die erste vorgeschlagene Lösung, (set -o posix ; set) | less, der arbeitet, hat aber einen Nachteil: es sendet an das Endgerät-Steuercodes, so dass sie nicht korrekt angezeigt. So zum Beispiel, wenn es (wahrscheinlich) eine IFS=$' \t\n' Variable ist, können wir sehen:

IFS=' 
' 

... statt.

Meine egrep Lösung zeigt diese (und eventuell andere ähnliche) richtig.

+0

es ist 8 Jahre her, Sie wissen – lauriys

+0

** Downvoted, weil es einfach falsch ist ** 'bash -c $ 'a() {echo" \ nA = B "; }; unscharf A; einstellen | egrep "^ \ w + =" '| grep^A' zeigt 'A = B" '-> Fail! – Tino

0

Ich habe wahrscheinlich the answer Vor einiger Zeit gestohlen ... wie auch immer etwas anders als 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" 
    } 
3

Basierend auf einige der oben genannten Antworten, das ist für mich gearbeitet:

before=$(set -o posix; set | sort); 

Quelle Datei:

comm -13 <(printf %s "$before") <(set -o posix; set | sort | uniq) 
0

Hier ist so mething ähnlich der @GinkgoFr Antwort, aber ohne die von @Tino oder @DejayClayton identifizierten Probleme, und ist robuster als @ DouglasLeeder cleveren set -o posix Bit:

+ function SOLUTION() { (set +o posix; set) | sed -ne '/^\w\+=/!q; p;'; } 

Der Unterschied besteht darin, dass diese Lösung nach dem ersten nicht STOPPT -Variablenbericht, z die erste von set

gemeldet Funktion BTW: Das "Tino" -Problem ist gelöst. Obwohl POSIX ausgeschaltet ist und Funktionen von set, gemeldet werden, erlaubt der Teil der Lösung nur variable Berichte (z. B. VAR=VALUE Zeilen). Insbesondere die A2 tut nicht fälschlicherweise machen es in den Ausgang.

+ function a() { echo $'\nA2=B'; }; A0=000; A9=999; 
+ SOLUTION | grep '^A[0-9]=' 
A0=000 
A9=999 

UND: Die "DejayClayton" Problem gelöst ist (eingebettete Zeilenumbrüche in Variablenwerte tun nicht die Ausgabe stören - jeder VAR=VALUE eine einzige Ausgangsleitung erhalten):

+ A1=$'111\nA2=222'; A0=000; A9=999; 
+ SOLUTION | grep '^A[0-9]=' 
A0=000 
A1=$'111\nA2=222' 
A9=999 

HINWEIS: Die Lösung von @DouglasLeeder bereitgestellt, leidet unter dem "DejayClayton" -Problem (Werte mit eingebetteten Zeilenumbrüchen). Unten ist die A1 falsch und A2 sollte überhaupt nicht angezeigt werden.

$ A1=$'111\nA2=222'; A0=000; A9=999; (set -o posix; set) | grep '^A[0-9]=' 
A0=000 
A1='111 
A2=222' 
A9=999 

ENDLICH: Ich glaube nicht, die Version von bash Angelegenheiten, aber es könnte. Ich habe meine Prüfung/Entwicklung auf dieses ein:

$ bash --version 
GNU bash, version 4.4.12(1)-release (x86_64-pc-msys) 

POST-SCRIPT: einige der anderen Antworten auf die OP gegeben, ich bin < 100% sicher, dass links setimmer wandeln Zeilenumbrüche im Wert \n, auf die diese Lösung angewiesen ist, um das "DejayClayton" -Problem zu vermeiden. Vielleicht ist das ein modernes Verhalten? Oder eine Kompilierzeitvariation? Oder eine set -o oder shopt Optionseinstellung? Wenn Sie über solche Variationen wissen, fügen Sie bitte einen Kommentar ...

Verwandte Themen