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?

621voto

Humberto Romero Punkte 5205

Verwenden Sie die Aufrufsyntax "dot space script". Hier ein Beispiel, wie Sie den vollständigen Pfad zu einem Skript verwenden können:

. /path/to/set_env_vars.sh

Und so geht's, wenn Sie sich im selben Verzeichnis wie das Skript befinden:

. set_env_vars.sh

Diese führen das Skript unter der aktuellen Shell aus, anstatt eine andere zu laden (was passieren würde, wenn Sie ./set_env_vars.sh ). Da es in der gleichen Shell läuft, sind die von Ihnen gesetzten Umgebungsvariablen auch beim Beenden des Programms verfügbar.

Dies ist dasselbe wie der Aufruf source set_env_vars.sh aber es ist kürzer zu tippen und könnte an einigen Orten funktionieren, wo source nicht.

332voto

converter42 Punkte 7213

Ihr Shell-Prozess hat eine Kopie der Umgebung des Elternprozesses und keinerlei Zugriff auf die Umgebung des Elternprozesses. Wenn Ihr Shell-Prozess beendet wird, gehen alle Änderungen, die Sie an seiner Umgebung vorgenommen haben, verloren. Die Beschaffung einer Skriptdatei ist die gebräuchlichste Methode zur Konfiguration einer Shell-Umgebung; vielleicht möchten Sie in den sauren Apfel beißen und für jede der beiden Shell-Varianten eine anlegen.

61voto

Thomas Kammeyer Punkte 4397

Sie werden nicht in der Lage sein, die Shell des Aufrufers zu ändern, da sie sich in einem anderen Prozesskontext befindet. Wenn Kindprozesse die Variablen Ihrer Shell erben, erben sie erben sie selbst Kopien.

Eine Möglichkeit ist, ein Skript zu schreiben, das die richtigen Befehle für tcsh ausgibt oder sh ausgibt, je nachdem, wie es aufgerufen wird. Wenn Ihr Skript "setit" ist, dann tun Sie das:

ln -s setit setit-sh

y

ln -s setit setit-csh

Entweder direkt oder in einem Alias, tun Sie dies von sh

eval `setit-sh`

oder dies von csh

eval `setit-csh`

setit verwendet $0, um seinen Ausgabestil zu bestimmen.

Das erinnert daran, wie man früher die Umgebungsvariable TERM gesetzt hat.

Der Vorteil dabei ist, dass setit in einer beliebigen Shell geschrieben wird, wie in:

#!/bin/bash
arg0=$0
arg0=${arg0##*/}
for nv in \
   NAME1=VALUE1 \
   NAME2=VALUE2
do
   if [ x$arg0 = xsetit-sh ]; then
      echo 'export '$nv' ;'
   elif [ x$arg0 = xsetit-csh ]; then
      echo 'setenv '${nv%%=*}' '${nv##*=}' ;'
   fi
done

mit den oben angegebenen symbolischen Links und dem eval des in Backquotes gesetzten Ausdrucks führt dies zum gewünschten Ergebnis.

Zur Vereinfachung des Aufrufs für csh, tcsh oder ähnliche Shells:

alias dosetit 'eval `setit-csh`'

oder für sh, bash und dergleichen:

alias dosetit='eval `setit-sh`'

Das Schöne daran ist, dass Sie die Liste nur an einer Stelle pflegen müssen. Theoretisch könnten Sie die Liste sogar in einer Datei ablegen und cat nvpairfilename zwischen "in" und "do".

Das ist so ziemlich die Art und Weise, wie die Einstellungen für das Login-Shell-Terminal vorgenommen wurden: Ein Skript gibt Anweisungen aus, die in der Login-Shell ausgeführt werden. Um den Aufruf zu vereinfachen, wird in der Regel ein Alias verwendet, wie z.B. "tset vt100". Wie in einer anderen Antwort erwähnt, gibt es eine ähnliche Funktionalität auch im INN UseNet Newsserver.

50voto

chris Punkte 501

In meinem .bash_profile habe ich :

# No Proxy
function noproxy
{
    /usr/local/sbin/noproxy  #turn off proxy server
    unset http_proxy HTTP_PROXY https_proxy HTTPs_PROXY
}

# Proxy
function setproxy
{
    sh /usr/local/sbin/proxyon  #turn on proxy server 
    http_proxy=http://127.0.0.1:8118/
    HTTP_PROXY=$http_proxy
    https_proxy=$http_proxy
    HTTPS_PROXY=$https_proxy
    export http_proxy https_proxy HTTP_PROXY HTTPS_PROXY
}

Wenn ich also den Proxy deaktivieren möchte, die Funktion(en) in der Login-Shell ausgeführt und setzen die Variablen wie erwartet und gewünscht.

36voto

Kjetil Joergensen Punkte 1575

Es ist "irgendwie" möglich durch die Verwendung von gdb und setenv(3) obwohl es mir schwer fällt, dies tatsächlich zu empfehlen. (Zusätzlich, d.h. das aktuellste Ubuntu lässt dies nicht zu, ohne dem Kernel zu sagen, dass er bei ptrace freizügiger sein soll, und das Gleiche gilt vielleicht auch für andere Distributionen).

$ cat setfoo
#! /bin/bash

gdb /proc/${PPID}/exe ${PPID} <<END >/dev/null
call setenv("foo", "bar", 0)
END
$ echo $foo

$ ./setfoo
$ echo $foo
bar

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