569 Stimmen

Kann ein Shell-Skript Umgebungsvariablen der aufrufenden Shell setzen?

Ich versuche, ein Shell-Skript zu schreiben, das, wenn es ausgeführt wird, einige Umgebungsvariablen setzt, die in der Shell des Aufrufers gesetzt bleiben.

setenv FOO foo

in csh/tcsh, oder

export FOO=foo

in sh/bash nur während der Ausführung des Skripts setzen.

Ich weiß bereits, dass

source myscript

führt die Befehle des Skripts aus, anstatt eine neue Shell zu starten, und das kann dazu führen, dass die Umgebung des "Aufrufers" festgelegt wird.

Aber hier ist der Haken:

Ich möchte, dass dieses Skript entweder von bash oder csh aus aufgerufen werden kann. Mit anderen Worten, ich möchte, dass Benutzer einer der beiden Shells mein Skript ausführen können und dass sich die Umgebung ihrer Shells ändert. Source" wird also nicht funktionieren, da ein Benutzer, der csh ausführt, kein Bash-Skript aufrufen kann und ein Benutzer, der bash ausführt, kein csh-Skript aufrufen kann.

Gibt es eine vernünftige Lösung, bei der man nicht ZWEI Versionen des Skripts schreiben und pflegen muss?

3voto

Marton Tatai Punkte 170

Unter OS X bash können Sie folgendes tun:
Erstellen Sie die Bash-Skriptdatei, um die Variable zu deaktivieren

#!/bin/bash
unset http_proxy

Die Datei ausführbar machen

sudo chmod 744 unsetvar

Alias erstellen

alias unsetvar='source /your/path/to/the/script/unsetvar'

Es sollte sofort einsatzbereit sein, sofern Sie den Ordner, der Ihre Skriptdatei enthält, an den Pfad angehängt haben.

2voto

Oleg Chirukhin Punkte 930

Sie können eine andere Bash mit dem anderen bash_profile aufrufen. Sie können auch spezielle bash_profile für die Verwendung in einer Umgebung mit mehreren Bashprofilen erstellen.

Denken Sie daran, dass Sie Folgendes verwenden können Funktionen innerhalb von bashprofile, und die Funktionen werden global verfügbar sein. Zum Beispiel kann "function user { export USER_NAME $1 }" eine Variable zur Laufzeit setzen, zum Beispiel: user olegchir && env | grep olegchir

2voto

Howard Hobbes Punkte 21

Eine weitere Möglichkeit ist die Verwendung von "Umgebungsmodulen" ( http://modules.sourceforge.net/ ). Damit wird leider eine dritte Sprache in den Mix eingeführt. Sie definieren die Umgebung mit der Sprache von Tcl, aber es gibt ein paar praktische Befehle für typische Änderungen (prepend vs. append vs. set). Außerdem müssen Sie Umgebungsmodule installiert haben. Sie können dann module load *XXX* um die gewünschte Umgebung zu benennen. Der Modul-Befehl ist im Grunde ein schicker Alias für den Befehl eval Mechanismus, der oben von Thomas Kammeyer beschrieben wurde. Der Hauptvorteil ist, dass man die Umgebung in einer Sprache pflegen kann und sich auf "Umgebungsmodule" verlassen kann, um sie in sh, ksh, bash, csh, tcsh, zsh, python (?!?!!) usw. zu übersetzen.

2voto

Ich habe eine Lösung mit Pipes, Eval und Signal entwickelt.

parent() {
    if [ -z "$G_EVAL_FD" ]; then
            die 1 "Rode primeiro parent_setup no processo pai"
    fi
    if [ $(ppid) = "$$" ]; then
            "$@"
    else
            kill -SIGUSR1 $$
            echo "$@">&$G_EVAL_FD
    fi
}
parent_setup() {
    G_EVAL_FD=99
    tempfile=$(mktemp -u)
    mkfifo "$tempfile"
    eval "exec $G_EVAL_FD<>'$tempfile'"
    rm -f "$tempfile"
    trap "read CMD <&$G_EVAL_FD; eval \"\$CMD\"" USR1
}
parent_setup #on parent shell context
( A=1 ); echo $A # prints nothing
( parent A=1 ); echo $A # prints 1

Es kann mit jedem Befehl funktionieren.

2voto

tripleee Punkte 155951

Ich sehe keine Antwort, die dokumentiert, wie man dieses Problem mit kooperierenden Prozessen umgehen kann. Ein häufiges Muster bei Dingen wie ssh-agent ist, dass der untergeordnete Prozess einen Ausdruck ausgibt, den der übergeordnete Prozess eval .

bash$ eval $(shh-agent)

Zum Beispiel, ssh-agent hat Optionen zur Auswahl einer Csh- oder Bourne-kompatiblen Ausgabesyntax.

bash$ ssh-agent
SSH2_AUTH_SOCK=/tmp/ssh-era/ssh2-10690-agent; export SSH2_AUTH_SOCK;
SSH2_AGENT_PID=10691; export SSH2_AGENT_PID;
echo Agent pid 10691;

(Dadurch wird der Agent gestartet, aber Sie können ihn nicht verwenden, es sei denn, Sie fügen diese Ausgabe per Copy-Paste in Ihre Shell-Eingabeaufforderung ein). Vergleichen Sie:

bash$ ssh-agent -c
setenv SSH2_AUTH_SOCK /tmp/ssh-era/ssh2-10751-agent;
setenv SSH2_AGENT_PID 10752;
echo Agent pid 10752;

(Wie Sie sehen können, csh y tcsh utilise setenv um Variablen zu setzen).

Auch Ihr eigenes Programm kann dies tun.

bash$ foo=$(makefoo)

Votre makefoo Skript würde einfach den Wert berechnen und ausdrucken und den Aufrufer damit machen lassen, was er will - die Zuweisung an eine Variable ist ein üblicher Anwendungsfall, aber wahrscheinlich nichts, was Sie in das Werkzeug, das den Wert erzeugt, fest einprogrammieren wollen.

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