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?

17voto

Jonathan Leffler Punkte 694013

Das funktioniert - es ist nicht das, was ich verwenden würde, aber es "funktioniert". Lassen Sie uns ein Skript erstellen teredo zum Setzen der Umgebungsvariablen TEREDO_WORMS :

#!/bin/ksh
export TEREDO_WORMS=ukelele
exec $SHELL -i

Sie wird von der Korn-Shell interpretiert, exportiert die Umgebungsvariable und ersetzt sich dann selbst durch eine neue interaktive Shell.

Bevor wir dieses Skript ausführen, müssen wir SHELL in der Umgebung der C-Shell gesetzt, und die Umgebungsvariable TEREDO_WORMS nicht gesetzt ist:

% env | grep SHELL
SHELL=/bin/csh
% env | grep TEREDO
%

Wenn das Skript ausgeführt wird, befinden Sie sich in einer neuen Shell, einer anderen interaktiven C-Shell, aber die Umgebungsvariable ist gesetzt:

% teredo
% env | grep TEREDO
TEREDO_WORMS=ukelele
%

Wenn Sie diese Shell verlassen, wird die ursprüngliche Shell übernommen:

% exit
% env | grep TEREDO
%

Die Umgebungsvariable ist in der ursprünglichen Shell-Umgebung nicht gesetzt. Wenn Sie exec teredo um den Befehl auszuführen, dann wird die ursprüngliche interaktive Shell durch die Korn-Shell ersetzt, die die Umgebung festlegt, und diese wiederum wird durch eine neue interaktive C-Shell ersetzt:

% exec teredo
% env | grep TEREDO
TEREDO_WORMS=ukelele
%

Wenn Sie eingeben exit (oder Control-D ), dann wird Ihre Shell beendet, wobei Sie wahrscheinlich aus diesem Fenster ausgeloggt werden, oder Sie kehren zur vorherigen Ebene der Shell zurück, von der aus die Experimente gestartet wurden.

Der gleiche Mechanismus funktioniert für die Bash oder die Korn-Shell. Es kann vorkommen, dass die Eingabeaufforderung nach den Exit-Befehlen an seltsamen Stellen erscheint.


Beachten Sie die Diskussion in den Kommentaren. Dies ist keine Lösung, die ich empfehlen würde, aber sie erfüllt den erklärten Zweck eines einzigen Skripts zum Einstellen der Umgebung, das mit allen Shells funktioniert (die das -i Option, um eine interaktive Shell zu erstellen). Sie könnten auch Folgendes hinzufügen "$@" nach der Option, andere Argumente weiterzugeben, wodurch die Shell als allgemeines Werkzeug zum Setzen der Umgebung und Ausführen von Befehlen verwendet werden kann. Vielleicht möchten Sie die Option -i wenn es weitere Argumente gibt, die zu:

#!/bin/ksh
export TEREDO_WORMS=ukelele
exec $SHELL "${@-'-i'}"

Le site "${@-'-i'}" Bit bedeutet: "Wenn die Argumentliste mindestens ein Argument enthält, ist die ursprüngliche Argumentliste zu verwenden; andernfalls ist sie durch -i für die nicht vorhandenen Argumente".

13voto

Davide Punkte 16204

Sie sollten Module verwenden, siehe http://modules.sourceforge.net/

EDIT: Das Modulpaket wurde seit 2012 nicht mehr aktualisiert, funktioniert aber immer noch gut für die Grundlagen. Alle neuen Funktionen, Schnickschnack passieren in lmod diesen Tag (die ich mag es mehr): https://www.tacc.utexas.edu/research-development/tacc-projects/lmod

11voto

dkinzer Punkte 30335

Eine weitere Abhilfe, die nicht erwähnt wird, besteht darin, den Variablenwert in eine Datei zu schreiben.

Ich bin auf ein sehr ähnliches Problem gestoßen, bei dem ich in der Lage sein wollte, den letzten Test (anstelle aller meiner Tests) durchzuführen. Mein erster Plan war, einen Befehl zu schreiben, um die Umgebungsvariable TESTCASE zu setzen, und dann einen weiteren Befehl zu schreiben, der diese Variable zur Ausführung des Tests verwendet. Unnötig zu sagen, dass ich genau das gleiche Problem hatte wie Sie.

Aber dann kam ich auf diesen einfachen Trick:

Erster Befehl ( testset ):

#!/bin/bash

if [ $# -eq 1 ]
then
  echo $1 > ~/.TESTCASE
  echo "TESTCASE has been set to: $1"
else
  echo "Come again?"
fi

Zweiter Befehl ( testrun ):

#!/bin/bash

TESTCASE=$(cat ~/.TESTCASE)
drush test-run $TESTCASE

3voto

cristobal Punkte 486

Fügen Sie die Flagge -l oben in Ihr Bash-Skript ein, d. h.

#!/usr/bin/env bash -l

...

export NAME1="VALUE1"
export NAME2="VALUE2"

Die Werte mit NAME1 y NAME2 werden nun in Ihre aktuelle Umgebung exportiert, aber diese Änderungen sind nicht dauerhaft. Wenn Sie möchten, dass sie dauerhaft sind, müssen Sie sie zu Ihrer .bashrc Datei oder einer anderen Init-Datei.

Aus den Man Pages:

-l Make bash act as if it had been invoked as a login shell (see INVOCATION below).

3voto

klaus se Punkte 2421

Sie können den Kindprozess anweisen, seine Umgebungsvariablen auszudrucken (indem Sie "env" aufrufen), dann eine Schleife über die gedruckten Umgebungsvariablen im Elternprozess laufen lassen und "export" für diese Variablen aufrufen.

Der folgende Code basiert auf Erfassen der Ausgabe von find . -print0 in ein Bash-Array

Wenn die übergeordnete Shell die Bash ist, können Sie

while IFS= read -r -d $'\0' line; do
    export "$line"
done < <(bash -s <<< 'export VARNAME=something; env -0')
echo $VARNAME

Wenn die übergeordnete Shell der Bindestrich ist, dann read bietet nicht das Flag -d und der Code wird komplizierter

TMPDIR=$(mktemp -d)
mkfifo $TMPDIR/fifo
(bash -s << "EOF"
    export VARNAME=something
    while IFS= read -r -d $'\0' line; do
        echo $(printf '%q' "$line")
    done < <(env -0)
EOF
) > $TMPDIR/fifo &
while read -r line; do export "$(eval echo $line)"; done < $TMPDIR/fifo
rm -r $TMPDIR
echo $VARNAME

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