Serialisieren Sie die Shell-Variable in bash oder zsh

12

Gibt es eine Möglichkeit, eine Shell-Variable zu serialisieren? Angenommen, ich habe eine Variable $VARund möchte sie in einer Datei oder in einem anderen Format speichern und später erneut lesen, um denselben Wert wiederzuerlangen.

Gibt es eine tragbare Möglichkeit, dies zu tun? (Ich glaube nicht)

Gibt es eine Möglichkeit, dies in bash oder zsh zu tun?

fwenom
quelle
2
Achtung: Die Version meiner Antwort, die Sie gestern angenommen haben, hatte ein ernstes Problem, das in einigen Szenarien zum Erliegen kommen wird. Ich habe es umgeschrieben, um Korrekturen zu enthalten (und Features hinzuzufügen), und Sie sollten es wirklich von Grund auf neu lesen und Ihren Code portieren, um die feste Version zu verwenden.
Caleb
^ Ein weiteres ^ Beispiel für die aufrechte Staatsbürgerschaft von @ Caleb.
mikeserv

Antworten:

14

Warnung: Bei jeder dieser Lösungen müssen Sie sich bewusst sein, dass Sie der Integrität der Datendateien vertrauen, um sicher zu sein, da diese in Ihrem Skript als Shell-Code ausgeführt werden. Ihre Sicherheit ist von größter Bedeutung für die Sicherheit Ihres Skripts!

Einfache Inline-Implementierung zum Serialisieren einer oder mehrerer Variablen

Ja, sowohl in bash als auch in zsh können Sie den Inhalt einer Variablen auf eine Weise serialisieren, die mit dem typesetBuiltin und dem -pArgument leicht abgerufen werden kann . Das Ausgabeformat ist so, dass Sie einfach sourcedie Ausgabe durchführen können, um Ihre Daten wieder zu erhalten.

 # You have variable(s) $FOO and $BAR already with your stuff
 typeset -p FOO BAR > ./serialized_data.sh

Du kannst deine Sachen entweder später in deinem Skript oder in einem anderen Skript zurückbekommen:

# Load up the serialized data back into the current shell
source serialized_data.sh

Dies funktioniert für bash, zsh und ksh, einschließlich der Übergabe von Daten zwischen verschiedenen Shells. Bash übersetzt dies in seine eingebaute declareFunktion, während zsh dies implementiert, typesetaber da bash einen Alias ​​hat, funktioniert dies so oder so, wie wir es typesethier aus Gründen der ksh-Kompatibilität verwenden.

Komplexere verallgemeinerte Implementierung mit Funktionen

Die obige Implementierung ist sehr einfach. Wenn Sie sie jedoch häufig aufrufen, möchten Sie sich möglicherweise eine Utility-Funktion geben, um sie zu vereinfachen. Wenn Sie jemals versuchen, die oben genannten Funktionen in benutzerdefinierte Funktionen einzubeziehen, treten außerdem Probleme mit dem Variablenumfang auf. Diese Version sollte diese Probleme beseitigen.

Beachten Sie, dass zur Aufrechterhaltung der Bash / Zsh-Kreuzkompatibilität beide Fälle behoben werden typesetund declareder Code daher in einer oder beiden Shells funktionieren sollte. Dies fügt etwas Masse und Unordnung hinzu, die beseitigt werden könnten, wenn Sie dies nur für die eine oder andere Shell tun würden.

Das Hauptproblem bei der Verwendung von Funktionen hierfür (oder beim Einbeziehen des Codes in andere Funktionen) besteht darin, dass die typesetFunktion Code generiert, der standardmäßig eine lokale Variable und keine globale Variable erstellt, wenn er aus einer Funktion in ein Skript zurückgeleitet wird.

Dies kann mit einem von mehreren Hacks behoben werden. Mein anfänglicher Versuch, dies zu beheben, bestand darin, die Ausgabe des Serialisierungsprozesses zu analysieren sed, um das -gFlag hinzuzufügen, sodass der erstellte Code eine globale Variable definiert, wenn er zurückgegeben wird.

serialize() {
    typeset -p "$1" | sed -E '0,/^(typeset|declare)/{s/ / -g /}' > "./serialized_$1.sh"
}
deserialize() {
    source "./serialized_$1.sh"
}

Beachten Sie, dass der flippige sedAusdruck nur mit dem ersten Vorkommen von 'typeset' oder 'declare' übereinstimmen und -gals erstes Argument hinzufügen soll . Es ist nur erforderlich, das erste Vorkommen abzugleichen, da es , wie Stéphane Chazelas in Kommentaren zutreffend ausgeführt hat, auch Fälle abdeckt, in denen der serialisierte String wörtliche Zeilenumbrüche enthält, denen das Wort declare oder typeset folgt.

Neben meinem ersten Parsing zu korrigieren Fauxpas , Stéphane auch vorgeschlagen , einen weniger spröden Weg , dies zu hacken , dass nicht nur Seite Schritte , um die Probleme mit den Saiten Parsen aber könnte eine nützliche Haken sein , zusätzliche Funktionalität hinzufügen , indem Sie eine Wrapper - Funktion mit den Aktionen neu zu definieren Dies setzt voraus, dass Sie keine anderen Spiele mit den Befehlen declare oder typeset spielen. Diese Technik wäre jedoch einfacher zu implementieren, wenn Sie diese Funktionalität als Teil einer anderen eigenen Funktion oder als Teil einer anderen Funktion einbinden würden Sie hatten keine Kontrolle darüber, welche Daten geschrieben wurden und ob das -gFlag hinzugefügt wurde oder nicht . Ähnliches könnte auch mit Aliasen geschehen, siehe Gilles 'Antwort für eine Implementierung.

Um das Ergebnis noch nützlicher zu machen, können wir mehrere Variablen durchlaufen, die an unsere Funktionen übergeben wurden, indem wir davon ausgehen, dass jedes Wort im Argumentarray ein Variablenname ist. Das Ergebnis sieht ungefähr so ​​aus:

serialize() {
    for var in $@; do
        typeset -p "$var" > "./serialized_$var.sh"
    done
}

deserialize() {
    declare() { builtin declare -g "$@"; }
    typeset() { builtin typeset -g "$@"; }
    for var in $@; do
        source "./serialized_$var.sh"
    done
    unset -f declare typeset
}

In beiden Fällen sieht die Verwendung folgendermaßen aus:

# Load some test data into variables
FOO=(an array or something)
BAR=$(uptime)

# Save it out to our serialized data files
serialize FOO BAR

# For testing purposes unset the variables to we know if it worked
unset FOO BAR

# Load  the data back in from out data files
deserialize FOO BAR

echo "FOO: $FOO\nBAR: $BAR"
Caleb
quelle
declareist das bashÄquivalent von ksh's typeset. bash, zshUnterstützt auch typesetso in dieser Hinsicht typesetmehr tragbar ist. export -pist POSIX, aber es braucht kein Argument und seine Ausgabe ist shellabhängig (obwohl es für POSIX-Shells gut spezifiziert ist, zum Beispiel, wenn bash oder ksh als aufgerufen wird sh). Denken Sie daran, Ihre Variablen anzugeben. Die Verwendung des split + glob-Operators ist hier nicht sinnvoll.
Stéphane Chazelas
Beachten Sie, dass -Enur in einigen BSDs gefunden wird sed. Variablenwerte können Zeilenumbrüche enthalten, daher kann die korrekte Funktion sed 's/^.../.../'nicht garantiert werden.
Stéphane Chazelas
Genau das habe ich gesucht! Ich wollte eine bequeme Möglichkeit, Variablen zwischen Shells hin und her zu verschieben.
15.
Ich meinte: a=$'foo\ndeclare bar' bash -c 'declare -p a'für install wird eine zeile ausgegeben, die mit beginnt declare. Es ist wahrscheinlich besser, declare() { builtin declare -g "$@"; }bevor Sie anrufen source(und danach deaktivieren)
Stéphane Chazelas
2
@ Gilles, Aliase würden nicht in Funktionen funktionieren (müssen zum Zeitpunkt der Funktionsdefinition definiert werden), und mit bash würde dies bedeuten, dass Sie eine Aktion ausführen müssten, shopt -s expandaliaswenn Sie nicht interaktiv sind. Mit Funktionen können Sie den declareWrapper auch so erweitern, dass nur die von Ihnen angegebenen Variablen wiederhergestellt werden.
Stéphane Chazelas
3

Verwenden Sie Umleitung, Befehlssubstitution und Parametererweiterung. Doppelte Anführungszeichen sind erforderlich, um Leerzeichen und Sonderzeichen beizubehalten. Durch das Nachziehen werden xdie nachfolgenden Zeilenumbrüche gespeichert, die ansonsten bei der Befehlsersetzung entfernt würden.

#!/bin/bash
echo "$var"x > file
unset var
var="$(< file)"
var=${var%x}
Choroba
quelle
Wahrscheinlich möchte er den Variablennamen auch in der Datei speichern.
user80551
2

Alle serialisieren - POSIX

In jeder POSIX-Shell können Sie alle Umgebungsvariablen mit serialisieren export -p. Dies schließt nicht exportierte Shell-Variablen nicht ein. Die Ausgabe wird ordnungsgemäß in Anführungszeichen gesetzt, sodass Sie sie in derselben Shell zurücklesen und genau dieselben Variablenwerte abrufen können. Die Ausgabe ist in einer anderen Shell möglicherweise nicht lesbar, z. B. verwendet ksh die Nicht-POSIX- $'…'Syntax.

save_environment () {
  export -p >my_environment
}
restore_environment () {
  . ./my_environment
}

Serialisieren Sie einige oder alle - ksh, bash, zsh

Ksh (sowohl pdksh / mksh als auch ATT ksh), bash und zsh bieten mit dem typeseteingebauten Code eine bessere Möglichkeit. typeset -pdruckt alle definierten Variablen und ihre Werte aus (zsh lässt die Werte von Variablen aus, die mit ausgeblendet wurden typeset -H). Die Ausgabe enthält eine ordnungsgemäße Deklaration, damit Umgebungsvariablen beim Zurücklesen exportiert werden (wenn eine Variable jedoch bereits beim Zurücklesen exportiert wird, wird sie nicht unexportiert), sodass Arrays als Arrays usw. zurückgelesen werden. Hier auch die Ausgabe wird korrekt zitiert, ist aber garantiert nur in derselben Shell lesbar. Sie können eine Reihe von Variablen zum Serialisieren in der Befehlszeile übergeben. Wenn Sie keine Variable übergeben, werden alle serialisiert.

save_some_variables () {
  typeset -p VAR OTHER_VAR >some_vars
}

In bash und zsh kann eine Funktion nicht wiederhergestellt werden, da typesetAnweisungen in einer Funktion auf diese Funktion beschränkt sind. Sie müssen . ./some_varsin dem Kontext ausgeführt werden, in dem Sie die Werte der Variablen verwenden möchten, und dabei darauf achten, dass Variablen, die beim Export global waren, erneut als global deklariert werden. Wenn Sie die Werte innerhalb einer Funktion zurücklesen und exportieren möchten, können Sie einen temporären Alias ​​oder eine temporäre Funktion deklarieren. In zsh:

restore_and_make_all_global () {
  alias typeset='typeset -g'
  . ./some_vars
  unalias typeset
}

In der Bash (die declareeher verwendet als typeset):

restore_and_make_all_global () {
  alias declare='declare -g'
  shopt -s expand_aliases
  . ./some_vars
  unalias declare
}

Deklariert in ksh typesetlokale Variablen in mit definierten Funktionen function function_name { … }und globale Variablen in mit definierten Funktionen function_name () { … }.

Serialisieren Sie einige - POSIX

Wenn Sie mehr Kontrolle wünschen, können Sie den Inhalt einer Variablen manuell exportieren. Um den Inhalt einer Variablen genau in eine Datei zu drucken, verwenden Sie die integrierte printfFunktion ( echoenthält einige Sonderfälle, z. B. echo -neinige Shells, und fügt eine neue Zeile hinzu):

printf %s "$VAR" >VAR.content

Sie können dies mit zurücklesen, mit der $(cat VAR.content)Ausnahme, dass die Befehlsersetzung nachfolgende Zeilenumbrüche entfernt. Um diese Falten zu vermeiden, sollten Sie dafür sorgen, dass die Ausgabe niemals mit einem Zeilenumbruch endet.

VAR=$(cat VAR.content && echo a)
if [ $? -ne 0 ]; then echo 1>&2 "Error reading back VAR"; exit 2; fi
VAR=${VAR%?}

Wenn Sie mehrere Variablen drucken möchten, können Sie diese in einfache Anführungszeichen setzen und alle eingebetteten einfachen Anführungszeichen durch ersetzen '\''. Diese Form des Zitierens kann in jede Bourne / POSIX-artige Shell zurückgelesen werden. Das folgende Snippet funktioniert in jeder POSIX-Shell. Es funktioniert nur für String-Variablen (und numerische Variablen in Shells, die über sie verfügen, obwohl sie als Strings zurückgelesen werden). Es wird nicht versucht, Array-Variablen in Shells zu behandeln, die über sie verfügen.

serialize_variables () {
  for __serialize_variables_x do
    eval "printf $__serialize_variables_x=\\'%s\\'\\\\n \"\$${__serialize_variables_x}\"" |
    sed -e "s/'/'\\\\''/g" -e '1 s/=.../=/' -e '$ s/...$//'
  done
}

Hier ist ein weiterer Ansatz, der keinen Unterprozess auslöst, sondern die Manipulation von Zeichenfolgen verstärkt.

serialize_variables () {
  for __serialize_variables_var do
    eval "__serialize_variables_tail=\${$__serialize_variables_var}"
    while __serialize_variables_quoted="$__serialize_variables_quoted${__serialize_variables_tail%%\'*}"
          [ "${__serialize_variables_tail%%\'*}" != "$__serialize_variables_tail" ]; do
      __serialize_variables_tail="${__serialize_variables_tail#*\'}"
      __serialize_variables_quoted="${__serialize_variables_quoted}'\\''"
    done
    printf "$__serialize_variables_var='%s'\n" "$__serialize_variables_quoted"
  done
}

Beachten Sie, dass bei Shells, die schreibgeschützte Variablen zulassen, eine Fehlermeldung angezeigt wird, wenn Sie versuchen, eine schreibgeschützte Variable zurückzulesen.

Gilles 'SO - hör auf böse zu sein'
quelle
Dies bringt Variablen wie $PWDund mit sich $_- bitte lesen Sie Ihre eigenen Kommentare weiter unten.
mikeserv
@Caleb Wie wäre es mit typeseteinem Alias ​​für typeset -g?
Gilles 'SO- hör auf böse zu sein'
@ Gilles Daran habe ich gedacht, nachdem Stephanie die Funktionsmethode vorgeschlagen hatte, aber ich war mir nicht sicher, wie ich die erforderlichen Alias-Erweiterungsoptionen portabel über Shells setzen sollte. Vielleicht könnten Sie das in Ihre Antwort als eine sinnvolle Alternative zu der von mir eingeschlossenen Funktion einfügen.
Caleb
0

Vielen Dank @ stéphane-Chazelas , die all Probleme mit meinen früheren Versuchen , wiesen darauf hin, das scheint jetzt an der Arbeit um ein Array zu stdout oder in eine Variable serialise.

Diese Technik analysiert die Eingabe nicht per Shell (im Gegensatz zu declare -a/ declare -p) und ist daher sicher gegen das böswillige Einfügen von Metazeichen in den serialisierten Text.

Hinweis: Zeilenumbrüche sind nicht entgangen, weil readLöschungen das \<newlines>Zeichenpaar, so -d ...muss stattdessen lesen übergeben werden, und dann werden unescaped Zeilenumbrüche erhalten.

All dies wird in der unserialiseFunktion verwaltet.

Es werden zwei magische Zeichen verwendet, das Feldtrennzeichen und das Datensatztrennzeichen (sodass mehrere Arrays zu demselben Stream serialisiert werden können).

Diese Zeichen können als definiert werden FS und RSaber auch nicht als newlineZeichen definiert werden , da eine mit Escape-Zeichen versehene neue Zeile durch gelöscht wird read.

Das Escape-Zeichen muss \der Backslash sein, da dies verwendet wird read, um zu verhindern, dass das Zeichen als Zeichen erkannt wird IFS.

serialise wird serialisieren "$@" auf stdout , serialise_towird auf die Variable serialisiert, die in benannt ist$1

serialise() {
  set -- "${@//\\/\\\\}" # \
  set -- "${@//${FS:-;}/\\${FS:-;}}" # ; - our field separator
  set -- "${@//${RS:-:}/\\${RS:-:}}" # ; - our record separator
  local IFS="${FS:-;}"
  printf ${SERIALIZE_TARGET:+-v"$SERIALIZE_TARGET"} "%s" "$*${RS:-:}"
}
serialise_to() {
  SERIALIZE_TARGET="$1" serialise "${@:2}"
}
unserialise() {
  local IFS="${FS:-;}"
  if test -n "$2"
  then read -d "${RS:-:}" -a "$1" <<<"${*:2}"
  else read -d "${RS:-:}" -a "$1"
  fi
}

und unserialisieren mit:

unserialise data # read from stdin

oder

unserialise data "$serialised_data" # from args

z.B

$ serialise "Now is the time" "For all good men" "To drink \$drink" "At the \`party\`" $'Party\tParty\tParty'
Now is the time;For all good men;To drink $drink;At the `party`;Party   Party   Party:

(ohne abschließende Newline)

lies es zurück:

$ serialise_to s "Now is the time" "For all good men" "To drink \$drink" "At the \`party\`" $'Party\tParty\tParty'
$ unserialise array "$s"
$ echo "${array[@]/#/$'\n'}"

Now is the time 
For all good men 
To drink $drink 
At the `party` 
Party   Party   Party

oder

unserialise array # read from stdin

Bash's readrespektiert den Escape-Charakter\ (es sei denn, Sie übergeben das Flag -r), um die spezielle Bedeutung von Zeichen zu entfernen, z. B. für die Trennung von Eingabefeldern oder die Begrenzung von Zeilen.

Wenn Sie ein Array anstelle einer einfachen Argumentliste serialisieren möchten, übergeben Sie Ihr Array einfach als Argumentliste:

serialise_array "${my_array[@]}"

Sie können diese Funktion unserialisein einer Schleife wie readgewohnt verwenden, da es sich nur um einen umbrochenen Lesevorgang handelt. Beachten Sie jedoch, dass der Stream nicht durch Zeilenumbrüche getrennt ist:

while unserialise array
do ...
done
Sam Liddicott
quelle
Es funktioniert nicht, wenn die Elemente nicht druckbare (im aktuellen Gebietsschema) oder Steuerzeichen wie TAB oder Newline enthalten bashund zshdiese als rendern $'\xxx'. Versuchen Sie es mit bash -c $'printf "%q\n" "\t"'oderbash -c $'printf "%q\n" "\u0378"'
Stéphane Chazelas
verdammt noch mal, du hast recht! Ich werde meine Antwort ändern, um nicht printf% q, sondern $ {@ // .. / ..} Iterationen zu verwenden, um stattdessen
Leerraum
Diese Lösung hängt von $IFSder Unverändertheit ab und kann leere Array-Elemente jetzt nicht mehr ordnungsgemäß wiederherstellen. Tatsächlich wäre es sinnvoller, einen anderen Wert von IFS zu verwenden und -d ''zu vermeiden, dass Newline umgangen werden muss. Verwenden Sie zum Beispiel :als Feldtrennzeichen und lassen Sie nur diesen und den umgekehrten Schrägstrich unberührt und verwenden Sie ihn IFS=: read -ad '' arrayzum Importieren.
Stéphane Chazelas
Ja ... ich habe vergessen, dass Leerzeichen bei der Verwendung als Feldtrennzeichen beim Lesen zu einer Sonderbehandlung werden. Ich bin froh, dass Sie heute am Ball sind! Sie haben Recht mit -d "", um ein Entkommen zu vermeiden, \ n aber in meinem Fall wollte ich einen Stream von Serialisierungen lesen - ich werde die Antwort jedoch anpassen. Vielen Dank!
Sam Liddicott
Wenn eine neue Zeile mit einem Escapezeichen versehen wird, kann sie nicht beibehalten werden. Sie wird nur einmal entfernt read. Mit backslash-newline for readkönnen Sie eine logische Zeile auf eine andere physische Zeile setzen. Edit: ah ich sehe das du das problem mit newline schon erwähnst.
Stéphane Chazelas
0

Sie könnten verwenden base64:

$ VAR="1/ 
,x"
$ echo "$VAR" | base64 > f
$ VAR=$(cat f | base64 -d)
$ echo "${VAR}X"
1/ 
,xX
Aleb
quelle
-2
printf 'VAR=$(cat <<\'$$VAR$$'\n%s\n'$$VAR$$'\n)' "$VAR" >./VAR.file

Eine andere Möglichkeit besteht darin, sicherzustellen, dass Sie alle 'harten Anführungszeichen wie folgt verarbeiten:

sed '"s/'"'/&"&"&/g;H;1h;$!d;g;'"s/.*/VAR='&'/" <<$$VAR$$ >./VAR.file
$VAR
$$VAR$$

Oder mit export:

env - "VAR=$VAR" sh -c 'export -p' >./VAR.file 

Die erste und zweite Option funktionieren in jeder POSIX-Shell, vorausgesetzt, der Wert der Variablen enthält keine Zeichenfolge:

"\n${CURRENT_SHELLS_PID}VAR${CURRENT_SHELLS_PID}\n" 

Die dritte Option sollte für jede POSIX-Shell funktionieren, kann jedoch versuchen, andere Variablen wie _oder zu definieren PWD. Die Wahrheit ist jedoch, dass die einzigen Variablen, die es zu definieren versucht, von der Shell selbst festgelegt und verwaltet werden - und selbst wenn Sie den exportWert für eine von ihnen importieren - wie $PWDzum Beispiel -, setzt die Shell sie einfach auf zurück den korrekten Wert trotzdem sofort ermitteln - versuchen Sie es PWD=any_valueund überzeugen Sie sich.

Und weil - zumindest bei GNUs bash- die Debug-Ausgabe automatisch in sichere Anführungszeichen gesetzt wird, um sie erneut in die Shell einzugeben, funktioniert dies unabhängig von der Anzahl der 'Anführungszeichen in "$VAR":

 PS4= VAR=$VAR sh -cx 'VAR=$VAR' 2>./VAR.file

$VAR kann später in jedem Skript, in dem der folgende Pfad gültig ist, auf den gespeicherten Wert gesetzt werden:

. ./VAR.file
mikeserv
quelle
Ich bin nicht sicher, was Sie im ersten Befehl versucht haben zu schreiben. $$ist die PID der laufenden Shell, hast du das Zitat falsch und gemein verstanden \$oder so? Der grundsätzliche Ansatz, ein Dokument hier zu verwenden, könnte funktionieren, aber es ist schwierig und kein Einzeilenmaterial: Unabhängig davon, was Sie als Endmarker auswählen, müssen Sie etwas auswählen, das nicht in der Zeichenfolge enthalten ist.
Gilles 'SO- hör auf böse zu sein'
Der zweite Befehl funktioniert nicht, wenn $VARenthält %. Der dritte Befehl funktioniert nicht immer mit Werten, die mehrere Zeilen enthalten (auch nach dem Hinzufügen der offensichtlich fehlenden Anführungszeichen).
Gilles 'SO - hör auf böse zu sein'
@ Gilles - ich weiß, es ist das PID - ich habe es als einfache Quelle zum Setzen eines eindeutigen Trennzeichens verwendet. Was meinst du mit "nicht immer" genau? Und ich verstehe nicht, welche doppelten Anführungszeichen fehlen - all das sind variable Zuweisungen. Doppelte Anführungszeichen verwirren nur die Situation in diesem Zusammenhang.
mikeserv
@Gilles - Ich ziehe die Zuweisungssache zurück - das ist ein Argument dafür env. Ich bin immer noch gespannt, was du mit den mehreren Zeilen meinst - sedlöscht jede Zeile VAR=bis zur letzten - damit alle Zeilen $VARweitergeleitet werden. Können Sie uns bitte ein Beispiel geben, das es zerstört?
mikeserv
Ah, entschuldigung, die dritte Methode funktioniert (mit der Zitatkorrektur). Nun, unter der Annahme , die Variablennamen (hier VAR) nicht geändert PWDoder _oder vielleicht auch andere , dass einige Schalen definieren. Die zweite Methode erfordert bash; Das Ausgabeformat von -vist nicht standardisiert (Bindestrich, ksh93, mksh und zsh funktionieren nicht).
Gilles 'SO- hör auf böse zu sein'
-2

Fast gleich, aber ein bisschen anders:

Aus Ihrem Skript:

#!/usr/bin/ksh 

save_var()
{

    (for ITEM in $*
    do
        LVALUE='${'${ITEM}'}'
        eval RVALUE="$LVALUE"
        echo "$ITEM=\"$RVALUE\""  
    done) >> $cfg_file
}

restore_vars()
{
    . $cfg_file
}

cfg_file=config_file
MY_VAR1="Test value 1"
MY_VAR2="Test 
value 2"

save_var MY_VAR1 MY_VAR2
MY_VAR1=""
MY_VAR2=""

restore_vars 

echo "$MY_VAR1"
echo "$MY_VAR2"

Diese obige Zeit wird getestet.

vadimbog
quelle
Ich kann sehen, dass du nicht getestet hast! Die Kernlogik funktioniert, aber das ist nicht das Schwierigste. Das Schwierige ist, die Dinge richtig zu zitieren, und Sie tun nichts davon. Versuchen Sie Variablen , deren Werte enthalten Zeilenumbrüche, ', *etc.
Gilles ‚SO- Anschlag, die bösen‘
echo "$LVALUE=\"$RVALUE\""soll auch die Zeilenumbrüche behalten und das Ergebnis in der cfg_file sollte so aussehen: MY_VAR1 = "Line1 \ nLine 2" Wenn also MY_VAR1 ausgewertet wird, enthält es auch die neuen Zeilen. Natürlich könnten Sie Probleme haben, wenn Ihr gespeicherter Wert selbst "char enthält. Aber auch das könnte erledigt werden.
Vadimbog
1
Übrigens, warum soll man etwas abstimmen, das die hier gestellte Frage richtig beantwortet? Oben funktioniert sehr gut für mich und überall in meinen Skripten zu verwenden?
Vadimbog