34 Stimmen

Bash: definition einer datei-lokalen variablen unsichtbar für das sourcing-skript

Sagen wir, dass ich eine Bash-Skriptdatei config.sh habe. Es sollte von anderen Skripten als Quelle verwendet werden, und die definierten Variablen werden zur Anpassung der Skripte auf höherer Ebene verwendet.

Das Problem ist, wenn config.sh eine temporäre Variable hat und ihr Name mit der Variable auf der höheren Ebene in Konflikt steht, bricht die auf der höheren Ebene.

config.sh:

TMP1=abc
CONFIG_INPUT_DIR="$TMP1"/in
CONFIG_OUTPUT_DIR="$TMP1"/out

Script auf der höheren Ebene:

TMP1=def
source config.sh
echo $TMP1

Das letzte echo gibt abc aus, nicht def.

Lösung 1

Meine aktuelle Lösung besteht darin, einen zufälligen String an den temporären Variablennamen anzuhängen, um Konflikte fast unmöglich zu machen. z. B. :

TMP1_vFc9Uiew=abc
CONFIG_INPUT_DIR="$TMP1_vFc9Uiew"/in
CONFIG_OUTPUT_DIR="$TMP1_vFc9Uiew"/out
unset TMP1_vFc9Uiew

was schmerzhaft ist und den Code schwer lesbar macht, zusätzlich perfekt zu sein.

Lösung 2 mit dem local-Stichwort

Nach einigen Recherchen habe ich das Stichwort local kennengelernt. Aber wenn ich TMP1 einfach als local deklariere, beschwert sich Bash, dass config.sh: Zeile 1: local: kann nur in einer Funktion verwendet werden.

Also ist meine andere Lösung, das gesamte Konfigurationsskript als Funktion zu umschließen:

function config_func_rZ0Yqkpm() {
  local TMP1=abc
  CONFIG_INPUT_DIR="$TMP1"/in
  CONFIG_OUTPUT_DIR="$TMP1"/out
}
config_func_rZ0Yqkpm
unset config_func_rZ0Yqkpm

was besser ist als die vorherige Lösung in Bezug auf Wartbarkeit und Lesbarkeit, aber auch eine gewisse Möglichkeit für Konflikte wie Lösung 1 besteht.

Frage

Ich möchte eine robustere und klügere Lösung kennen, ohne Möglichkeit für Konflikte.

Danke.

10voto

sarnold Punkte 99402

Ein Trick, den ich von dem keychain Dienstprogramm gelernt habe, besteht darin, ein Programm zu verwenden, um eine source-bare Datei aufzubauen, die nur die Variablen enthält, die Sie aus Ihrem Programm exportieren möchten. Sie könnten Ihr Skript ändern, um die Variablen, die Sie setzen möchten, mit echo anzuzeigen und dann die Ausgabe Ihres Programms zu sourcen:

$ echo $FOO

$ source <(echo FOO=bar)
$ echo $FOO
bar
$ 

Ich habe echo FOO=bar verwendet, um das größere Skript zu simulieren; Ihr Programm ist wahrscheinlich komplexer. Der wichtige Teil ist, dass Sie Ihr Programm so ändern müssen, dass es die Variablen und Werte ausgibt, die Sie setzen möchten, anstatt sie einfach festzulegen. Auf diese Weise können Sie entscheiden, welche Variablen Sie freigeben möchten und welche privaten bleiben sollen, jedoch auf Kosten eines weiteren Shell-Prozesses.

0 Stimmen

ssh-agent verwendet eine ähnliche Technik mit den Optionen -c und -s.

0 Stimmen

@jjlin: Danke! Ich dachte, Schlüsselbund war nicht genau der Ort, an dem ich es zuerst gesehen habe, aber es war der erste Ort, an dem ich die Dokumentation gefunden habe. :) Lustig, es steht direkt dort im ssh-agent Handbuch...

0 Stimmen

Soweit ich weiß, erfordert die Verwendung dieser Technik, dass der Aufrufer immer darauf achten muss, den Befehl source zu verwenden. Gibt es keine Technik, die es ermöglicht, die Umgebungsvariablen des Aufrufers ohne diese Unannehmlichkeiten zu ändern?

10voto

glenn jackman Punkte 221248

Sie könnten Variablen vermeiden und Funktionen in config.sh verwenden, um Ihre Werte zu speichern:

get_dirname() { echo "abc"; }
CONFIG_INPUT_DIR="$(get_dirname)/in"
CONFIG_OUTPUT_DIR="$(get_dirname)/out"
unset -f get_dirname

Wenn Sie immer noch Bedenken wegen Namenskonflikten bei Funktionen haben, hilft Ihnen das nicht wirklich.

8voto

glenn jackman Punkte 221248

Die "ssh-agent" Methode:

config.sh

#!/bin/bash
TMP=abc
printf "CONFIG_INPUT_DIR=%s/in\n" "$TMP"
printf "CONFIG_OUTPUT_DIR=%s/out\n" "$TMP"

Hauptprogramm:

TMP1=def
eval "$(config.sh)"
echo "$TMP1"

0 Stimmen

Sie würden ";" am Ende jeder printf-Anweisung einfügen, damit eval-Anweisungen durch ";" getrennt sind.

0 Stimmen

Was ich hätte tun sollen, ist die Befehlssubstitution in Anführungszeichen zu setzen, damit die Zeilenumbrüche erhalten bleiben. Das werde ich korrigieren.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X