Ich möchte, dass mein Skript eine Datei liest, die Schlüssel / Wert-Paare von Umgebungsvariablen enthält, die festgelegt werden sollen, und diese dann festlegt.
Bisher habe ich Folgendes:
#!/bin/bash
cat $1 | while read kv
do
key=${kv%=*}
val=`echo ${kv#*=} | sed 's/^"\|"$//g'`
export $key="$val"
done
Und ich möchte eine Datei wie diese lesen:
XAUTHLOCALHOSTNAME="localhost"
DISPLAY=":0"
XAUTHORITY="/tmp/some-XAuthority"
Ich benötige diese Variablen nur für die Dauer des Skripts im Gültigkeitsbereich, sodass ich das Problem des Festlegens einer Variablen im Skript für den übergeordneten Gültigkeitsbereich nicht lösen muss .
Nach meinen Tests liegt mein Problem wohl bei export $key="$val"
, daher brauche ich nur einen Ersatz für diese Leitung.
bash
shell-script
environment-variables
palswim
quelle
quelle
key=${kv%%=*}
ist besser alskey=${kv%=*}
weil %% und ## sich von% und # unterscheiden, ob der entfernte Teil ist das kürzeste oder längste abnehmbare TeilAntworten:
export $key=$val
sollte gut funktionieren inbash
. Ich vermute, Ihr Problem ist die Pipe (|
). Alle Befehle in einer Pipeline werden in einer Subshell ausgeführt. In Ihrem Beispiel gibt die Instanzbash
, in der Ihr Skript ausgeführt wird, zwei Unterschalen ab: eine fürcat $1
und eine für diewhile read ...
. Die Variablen werden in der Subshell zugewiesen und exportiert, in der die while-Schleife ausgeführt wird. Alle Variablen werden beim Beenden der Subshell sofort verworfen. Eine Möglichkeit, dies zu beheben, besteht darin, überhaupt keine Subshells zu erzeugen. Versuchen Sie statt einer nutzlosen Verwendung von cat stattdessen die Umleitung:BashFAQ 24 erklärt dies ausführlicher.
Ein alternativer Ansatz besteht darin, nur die Datei mit Exporten zu erstellen:
Das
<( )
ist Prozesssubstitution.Als zusätzliche Warnung, da Sie Umgebungsvariablen aus einem Argument lesen, müssen Sie sicherstellen, dass die Argumentdatei
$1
eine vertrauenswürdige Quelle ist, damit sie Ihrem Skript keine schlechten Dinge antun kann.quelle
cat
. Aber das Skript mit Umleitung funktioniert jetzt, danke!( jw013 hat bereits eine richtige Antwort gegeben , aber ich möchte auf einige weitere Probleme hinweisen.)
Die rechte Seite einer Pipeline wird in bash in einer eigenen Subshell ausgeführt (wie auch die meisten anderen Shells, mit Ausnahme von ATT ksh und zsh). Sie legen also die Umgebungsvariablen in der Subshell fest, die die Schleife ausführt, jedoch nicht im Haupt-Shell-Prozess.
Hier gibt es eine einfache Lösung, die die nutzlose Verwendung
cat
durch eine Umleitung ersetzt:Wenn Sie die Eingabe vorverarbeiten müssen, fügen Sie im Allgemeinen die Schleife und den Rest des Skripts (zumindest den Teil, der die geänderten Variablen benötigt) in einen Block ein.
Beachten Sie, dass
while read line; do …
die Eingabezeilen im Allgemeinen nicht vollständig durchlaufen werden. Siehe Warum wirdwhile IFS= read
so oft verwendet, anstattIFS=; while read..
? für eine Erklärung. Die richtige Redewendung zum Durchlaufen von Eingabezeilen lautetHier spielt das Entfernen von führenden und nachfolgenden Leerzeichen keine Rolle, da Ihre Beispieleingabe nicht angegeben werden sollte. Möglicherweise müssen Sie
-r
jedoch eine Backslash-Erweiterung vermeiden. Es ist möglich, dass dieswhile read line
tatsächlich eine korrekte Art ist, Ihre Eingabe zu lesen (aber ich vermute nur, wenn die Variablenwerte keine Zeilenumbrüche enthalten). Es ist auch möglich, dass Ihr Eingabeformat mehrdeutig oder komplexer zu analysieren ist. Überprüfen Sie, was passiert, wenn einer der Variablenwerte ein Zeilenumbruchzeichen, ein doppeltes Anführungszeichen oder einen Backslash enthält.Ein Punkt, an dem Sie die Eingabe definitiv entstellen, ist, wenn Sie den Wert extrahieren:
Zunächst müssen Sie doppelte Anführungszeichen um die Variablensubstitution verwenden :
echo "${kv#*=}"
; Andernfalls führt die Shell eine Wortaufteilung und Dateinamengenerierung (dh Globbing) durch. Zweitensecho
ist dies keine zuverlässige Methode zum Drucken einer Zeichenfolge, da einige Zeichenfolgen, die mit a beginnen,-
als Optionen behandelt werden und einige Shells eine Backslash-Erweiterung für das Argument ausführen. Eine zuverlässige und tragbare Methode zum Drucken einer Zeichenfolge istprintf %s "${kv#*=}"
. Wenn sich der Wert über mehrere Zeilen erstreckt, wirkt das sed-Programm auf jede einzelne Zeile, was falsch ist. Dies kann behoben werden, aber es gibt eine einfachere Methode, nämlich die String-Manipulationsfunktionen der Shell zu verwenden :val=${kv#*=}; val=${val#\"}; val=${val%\"}
.Unter der Annahme, dass Ihre Eingabe korrekt mit einer Ebene
read
analysiert wurde, können Sie sie auf einfachere Weise analysieren und dabei dieIFS
Einstellung zum Teilen jeder Zeile nutzen:quelle
Eine andere gute Option könnte sein, das
export
in die Datei zu legen und es zu beschaffen:und dann:
quelle
/ env
Skript
quelle