Antworten:
set
gibt die Variablen aus, leider werden auch die definierten Funktionen ausgegeben.
Glücklicherweise gibt der POSIX-Modus nur die Variablen aus:
( set -o posix ; set ) | less
In den Rohrleitungen less
oder Umleitung zu dem Sie die Optionen mögen.
Um die Variablen nur im Skript zu deklarieren:
( 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 basierend darauf :-))
VARS="`set -o posix ; set`"; source script; SCRIPT_VARS="`grep -vFe "$VARS" <<<"$(set -o posix ; set)" | grep -v ^VARS=`"; unset VARS;
. Dadurch werden die Variablen auch in einem speicherfertigen Format ausgegeben. Die Liste enthält die Variablen, die das Skript geändert hat (es hängt davon ab, ob dies wünschenswert ist)
source
, sollten Sie dies mit der Ausgabe von tun können declare -p
.
before=$(set -o posix; set); dosomestuff; diff <(echo "$before") <(set -o posix; set)
compgen -v
Es werden alle Variablen einschließlich der lokalen aufgelistet. Ich habe es aus der Liste der Variablen abrufen gelernt , deren Name einem bestimmten Muster entspricht , und es in meinem Skript verwendet .
compgen -v
Listet leider auch globale Variablen auf, die lokal nicht festgelegt wurden. Ich bin mir nicht sicher, ob dies ein langjähriger Fehler oder das gewünschte Verhalten ist.
for i in _ {a..z} {A..Z}; do eval "echo \${!$i@}" ; done | xargs printf "%s\n"
Dies muss alle Namen der Shell-Variablen drucken. Sie können eine Liste vor und nach dem Sourcing Ihrer Datei erhalten, genau wie mit "set", um zu unterscheiden, welche Variablen neu sind (wie in den anderen Antworten erläutert). Beachten Sie jedoch, dass eine solche Filterung mit diff einige Variablen herausfiltern kann, die Sie benötigen, die jedoch vor der Beschaffung Ihrer Datei vorhanden waren.
Wenn Sie in Ihrem Fall wissen, dass die Namen Ihrer Variablen mit "VARIABLE" beginnen, können Sie Ihr Skript als Quelle verwenden und Folgendes tun:
for var in ${!VARIABLE@}; do
printf "%s%q\n" "$var=" "${!var}"
done
UPDATE: Für reine BASH-Lösung (keine externen Befehle verwendet):
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})"
Basierend auf einigen der oben genannten Antworten hat dies für mich funktioniert:
before=$(set -o posix; set | sort);
Quelldatei :
comm -13 <(printf %s "$before") <(set -o posix; set | sort | uniq)
Wenn Sie nachbearbeiten können (wie bereits erwähnt), können Sie einfach set
am Anfang und am Ende Ihres Skripts einen Aufruf tätigen (jeweils eine andere Datei) und die beiden Dateien unterscheiden. Beachten Sie, dass dies immer noch etwas Rauschen enthält.
Sie können dies auch programmgesteuert tun. Um die Ausgabe nur auf Ihren aktuellen Bereich zu beschränken, müssten Sie einen Wrapper für die Variablenerstellung implementieren. Beispielsweise
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 ergibt
VAR1=abc
VAR2=bcd
VAR3=cde
Hier ist etwas Ähnliches wie die @ GinkgoFr-Antwort, jedoch ohne die von @Tino oder @DejayClayton identifizierten Probleme, und es ist robuster als das clevere set -o posix
Bit von @ DouglasLeeder :
+ function SOLUTION() { (set +o posix; set) | sed -ne '/^\w\+=/!q; p;'; }
Der Unterschied besteht darin, dass diese Lösung nach dem ersten nicht variablen Bericht, z. B. der ersten von set
Übrigens: Das "Tino" -Problem ist gelöst. Obwohl POSIX deaktiviert ist und Funktionen von gemeldet werden set
, sed ...
erlaubt der Teil der Lösung nur variable Berichte durch (z VAR=VALUE
. B. Zeilen). Insbesondere A2
schafft es das nicht fälschlicherweise in die Ausgabe.
+ function a() { echo $'\nA2=B'; }; A0=000; A9=999;
+ SOLUTION | grep '^A[0-9]='
A0=000
A9=999
UND: Die „DejayClayton“ Problem ist gelöst (eingebettete Zeilenumbrüche in Variablenwerte haben nicht stören die Ausgabe - jeweils VAR=VALUE
eine einzelne 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 von @DouglasLeeder bereitgestellte Lösung leidet unter dem Problem "DejayClayton" (Werte mit eingebetteten Zeilenumbrüchen). Unten ist das 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 denke nicht, dass die Version der bash
Dinge, aber es könnte. Ich habe meine Tests / Entwicklungen an diesem durchgeführt:
$ bash --version
GNU bash, version 4.4.12(1)-release (x86_64-pc-msys)
POST-SCRIPT: Angesichts einiger anderer Antworten auf das OP bin ich <100% sicher, dass set
immer Zeilenumbrüche innerhalb des Werts konvertiert werden \n
, auf den sich diese Lösung stützt, um das Problem "DejayClayton" zu vermeiden. Vielleicht ist das ein modernes Verhalten? Oder eine Variation zur Kompilierungszeit? Oder eine set -o
oder shopt
Option? Wenn Sie solche Variationen kennen, fügen Sie bitte einen Kommentar hinzu ...
Aus Sicht der Sicherheit entweder @ akostadinov die Antwort oder @ JuvenXu die Antwort auf Berufung auf die unstrukturierte Ausgang des vorzuziehen ist set
Befehl, aufgrund der folgenden potenziellen Sicherheitslücke:
#!/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
Mit der obigen Funktion doLogic
wird set
überprüft PS1
, ob eine Variable vorhanden ist, 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 neue Zeile enthält, die Ergebnisse vollständig verunreinigen kann.
Dies ist natürlich ein potenzielles Sicherheitsrisiko. Verwenden Sie stattdessen entweder die Unterstützung von Bash für die Erweiterung indirekter Variablennamen oder compgen -v
.
Versuchen Sie Folgendes: set | egrep "^\w+="
(mit oder ohne | less
Rohrleitung)
Die erste vorgeschlagene Lösung ( set -o posix ; set ) | less
funktioniert, hat jedoch einen Nachteil: Sie überträgt Steuercodes an das Terminal, sodass sie nicht richtig angezeigt werden. Wenn es zum Beispiel (wahrscheinlich) eine IFS=$' \t\n'
Variable gibt, können wir sehen:
IFS='
'
…stattdessen.
Meine egrep
Lösung zeigt dies (und eventuell andere ähnliche) richtig an.
bash -c $'a() { echo "\nA=B"; }; unset A; set | egrep "^\w+="' | grep ^A
Anzeigen handelt A=B"
-> Fail!
Ich habe die Antwort wahrscheinlich schon vor einiger Zeit gestohlen ... sowieso etwas anders als eine Funktion:
##
# 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"
}
Eine einfache Möglichkeit, dies zu tun, besteht darin, den Bash-Strict-Modus zu verwenden, indem Sie Systemumgebungsvariablen festlegen, bevor Sie Ihr Skript ausführen, und diff verwenden, um nur diejenigen Ihres Skripts zu sortieren:
# 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
Sie können jetzt Variablen Ihres Skripts in /tmp/script_vars.log abrufen. Oder zumindest etwas basierend darauf!
-o posix
jetzt ein Diff enthält nur die Variablen.