Was ist der beste distro- / shell-agnostische Weg, um Umgebungsvariablen zu setzen?

31

Die Frage sagt alles. Ich benutze derzeit Arch Linux und das zsh, aber ich hätte gerne eine Lösung, die (zumindest) sowohl auf VTs als auch in xterms funktioniert und auch (hoffentlich, vorzugsweise) weiterhin funktioniert, wenn ich Distributionen oder Shells wechsle.

Ich habe wild unterschiedliche Antworten auf diese Frage in den Dokumenten verschiedener Distributionen gehört. Ubuntu sagt "use .pam_environment". Ich denke in Arch, was sie empfehlen, hängt von Ihrer Muschel ab. Momentan füge ich alles in .profile ein und wenn eine Shell das aus irgendeinem Grund nicht erzeugt (zB bash, wenn .bash_profile existiert), überschreibe ich dies, indem ich es manuell beschaffe. Aber es scheint einen besseren Weg zu geben.

strugee
quelle
2
Das hat nichts mit Distribution zu tun und alles mit Shell. Ich bin mir jedoch nicht sicher, ob es eine tragbare Möglichkeit gibt.
Joseph R.
Hmm. Genial .
Strugee

Antworten:

29

Es gibt leider keinen vollständig portierbaren Speicherort zum Festlegen von Umgebungsvariablen. Die beiden Dateien, die am nächsten kommen ~/.profile, sind : Dies ist der traditionelle Speicherort, der bei vielen Setups sofort einsatzbereit ist, und ~/.pam_environmenteine moderne, alltägliche, aber eingeschränkte Alternative.

Was ist einzutragen? ~/.pam_environment

Die Datei ~/.pam_environmentwird von allen Anmeldemethoden gelesen, die PAM verwenden und für die diese Datei aktiviert ist. Dies gilt heutzutage für die meisten Linux-Systeme.

Der Hauptvorteil von ~/.pam_environmentist, dass es (wenn aktiviert) gelesen wird, bevor die Shell des Benutzers gestartet wird, sodass es unabhängig vom Sitzungstyp, der Anmeldeshell und anderen Komplexitäten funktioniert. Es funktioniert sogar für nicht interaktive Anmeldungen wie su -c somecommandund ssh somecommand.

Die größte Einschränkung ~/.pam_environmentbesteht darin, dass Sie dort nur einfache Zuweisungen vornehmen können, keine komplexe Shell-Syntax. Die Syntax dieser Datei lautet wie folgt.

  • Dateien werden zeilenweise analysiert.
  • Führende Leerzeichen werden ignoriert.
  • Sie können optional Zeilen mit exportund einem einzelnen Leerzeichen beginnen (kein Tabulator, go figure).
  • Danach muss jede Zeile die Form haben, VAR=VALUEin der VAR aus Buchstaben, Ziffern und Unterstrichen besteht.
  • # Beginnt ein Kommentar, kann er nicht in einem Wert erscheinen.
  • Wenn VALUE mit 'oder beginnt "und ein anderes identisches Anführungszeichen enthält, wird VAR auf die Zeichenfolge zwischen den Anführungszeichen gesetzt (alles, was nach dem zweiten Anführungszeichen folgt, wird ignoriert). Andernfalls wird VAR nach dem =Vorzeichen auf den String gesetzt .
  • Wenn dies nicht =der Fall ist, wird die Variable aus der Umgebung entfernt.

Auf der anderen Seite ~/.pam_environmentfunktioniert es also unter einer Vielzahl von Umständen. Auf der anderen Seite können Sie keine dynamischen Einstellungen vornehmen, z. B. den Wert einer Variablen auf eine andere Variable stützen (z. B. ein Verzeichnis zu PATH hinzufügen) oder die Ausgabe eines Befehls verwenden (z. B. testen, ob ein Verzeichnis oder ein Programm vorhanden ist) Zeichen ( #'", Zeilenvorschub) können nicht oder nur mühsam in den Wert eingegeben werden.

Was ist einzutragen? ~/.profile

Diese Datei sollte eine portable (POSIX) sh-Syntax haben. Verwenden Sie ksh- oder bash-Erweiterungen (Arrays [[ … ]]usw.) nur, wenn Sie wissen, dass Ihr System über diese Shells verfügt /bin/sh.

Diese Datei kann von Skripten in automatisierten Anwendungen gelesen werden, daher sollten keine Programme aufgerufen werden, die eine Ausgabe oder einen Aufruf erzeugen exec. Wenn Sie dies bei Anmeldungen im Textmodus tun möchten, tun Sie dies nur für interaktive Shells. Beispiel:

case $- in *i*)
  # Display a message if I have new mail
  if mail -e; then echo 'You have new mail'; fi
  # If zsh is available, and this looks like a text-mode login, run zsh
  case "`ps $PPID` " in
    *" login "*)
      if type zsh >/dev/null 2>/dev/null; then exec zsh; fi;;
  esac
esac

Dies ist ein Beispiel für die Verwendung /bin/shals Anmeldeshell und den Wechsel zu Ihrer bevorzugten Shell. Siehe auch, wie ich bash als Anmeldeshell verwenden kann, wenn mein Sysadmin es ablehnt, dies zu ändern

Wann wird ~/.profilebei nicht grafischer Anmeldung nicht gelesen?

Verschiedene Login-Shells lesen verschiedene Dateien.

Wenn Ihre Login-Shell bash ist

Bash liest ~/.bash_loginoder ~/.bash_profileob sie statt existieren ~/.profile. Bash liest ~/.bashrcauch dann keine Login-Shell ein, wenn sie interaktiv ist. Um sich diese Macken nie wieder merken zu müssen, erstellen Sie eine ~/.bash_profilemit den folgenden zwei Zeilen:

. ~/.profile
case $- in *i*) . ~/.bashrc;; esac

Siehe auch Welche Setup-Dateien sollten zum Einrichten von Umgebungsvariablen mit bash verwendet werden?

Wenn Ihre Login-Shell zsh ist

Zsh liest ~/.zprofileund ~/.zlogin, aber nicht ~/.profile. Zsh hat eine andere Syntax als sh, kann jedoch ~/.profileim sh-Emulationsmodus lesen . Sie können dies verwenden für ~/.zprofile:

emulate sh -c '. ~/.profile'

Siehe auch Zsh trifft nicht ~ / .profile

Wenn Ihre Login-Shell eine andere Shell ist

Sie können dort nicht viel tun, außer /bin/shals Anmeldeshell und als interaktive Shell Ihre Lieblingsshell (z. B. Fisch) zu verwenden. Das ist was ich mit zsh mache. Ein Beispiel zum Aufrufen einer anderen Shell von finden Sie oben ~/.profile.

Remote-Befehle

Wenn Sie einen Remote-Befehl aufrufen, ohne eine interaktive Shell zu durchlaufen, lesen nicht alle Shells eine Startdatei.

Ksh liest die von der ENVVariablen angegebene Datei , wenn Sie es schaffen, sie zu übergeben.

Bash liest, ~/.bashrcob es nicht interaktiv (!) Ist und sein übergeordneter Prozess rshdoder heißt sshd. So können Sie beginnen ~/.bashrcmit

if [[ $- != *i* ]]; then
  . ~/.profile
  return
fi

Zsh liest immer, ~/.zshenvwenn es anfängt. Seien Sie vorsichtig, da dies von jeder einzelnen Instanz von zsh gelesen wird, auch wenn es sich um eine Subshell handelt, in der Sie andere Variablen festgelegt haben. Wenn zsh Ihre Login-Shell ist und Sie damit Variablen nur für Remote-Befehle festlegen möchten, verwenden Sie einen Guard: Setzen Sie eine Variable in ~/.profile, z. B. MY_ENVIRONMENT_HAS_BEEN_SET=yes, und überprüfen Sie diesen Guard vor dem Lesen ~/.profile.

if [[ -z $MY_ENVIRONMENT_HAS_BEEN_SET ]]; then emulate sh -c '~/.profile'; fi

Der Fall der grafischen Anmeldungen

Viele Distributionen, Display-Manager und Desktop-Umgebungen können ausgeführt werden ~/.profile, indem sie entweder explizit aus den Startskripten ausgewählt oder eine Anmeldeshell ausgeführt werden.

Leider gibt es keine allgemeine Methode, um Distro / DM / DE-Kombinationen zu verarbeiten, bei denen ~/.profilenicht gelesen wird.

Wenn Sie eine herkömmliche Sitzung verwenden, die von gestartet wurde ~/.xsession, sollten Sie hier die Umgebungsvariablen festlegen. Tun Sie es durch Sourcing ~/.profile(dh . ~/.profile). Beachten Sie, dass in einigen Setups die Startskripte der Desktop-Umgebung ~/.profileerneut ausgeführt werden.

Gilles 'SO - hör auf böse zu sein'
quelle
Was bedeutet case $- in *i*)tun?
Qodeninja
2
@qodeninja Führt die folgenden Anweisungen aus (bis das Matching ;;oder esac), wenn es $-mit dem Muster übereinstimmt *i*, dh wenn es $-enthält i, dh wenn die Shell interaktiv ist.
Gilles 'SO- hör auf böse zu sein'
$-ist eine Zeichenfolge der aktuell festgelegten Shell-Optionen. (wie set -x). ibedeutet interaktive Shell.
Peter Cordes
Können Sie nicht einfach eine gemeinsame Datei erstellen ~/.config/env, auch ohne Emulation?
Kevin Suttle
1
@ StéphaneChazelas Das ist eine puristische Sichtweise. Ich halte mich .profilean ziemlich alte Bourne-Muscheln, aber ich erkenne, dass es einigen Leuten einfach egal ist. Ich habe nichts gegen Leute, die davon ausgehen, dass sh = bash für ihre eigenen Dateien ist. Es interessiert mich nur, ob sie Skripte veröffentlichen #!/bin/sh, die bash-Funktionen verwenden.
Gilles 'SO- hör auf böse zu sein'
4

Soweit mir bekannt ist, gibt es keinen distro- und shellunabhängigen Standard zum Setzen von Umgebungsvariablen.

Die häufigste und de - facto - Standard zu sein scheint /etc/profileund ~/.profile. Die zweithäufigste scheint zu sein , /etc/environmentund ~/.pam_environment.

Mir scheint, dass alle Unterlagen, die ich gefunden habe, Sie auch schon gefunden haben. Ich liste sie hier trotzdem für die anderen Leser auf.

  • Debian empfiehlt /etc/profileund ~/.profile( Link ).
  • Ubuntu empfiehlt /etc/environmentund ~/.pam_environment( Link ).
  • Arch Linux erwähnt unter anderem /etc/profileund /etc/environment( Link ).

Bonus: Ein Text, der die Verwendung und / oder den Missbrauch von /etc/environmentin Debian in Frage stellt ( Link , letzte Aktualisierung 2008).

lesmana
quelle
Unabhängig davon, welche Datei Sie verwenden, stoßen Sie immer noch auf inkompatible Syntax zwischen verschiedenen Shells.
Joseph R.
1
@ JosephR. behalten die meisten Shells nicht die Abwärtskompatibilität bei sh? Solange Sie sich an POSIX halten, hätte ich gedacht, dass es Ihnen gut geht ...
Evilsoup
1
AFAIK Sie können keine Variablen in cshund Freunde der POSIX-Art zuweisen (Sie brauchen etwas wie setoder setenv)
Joseph R.
0

Ich habe das folgende Skript ~ / bin / agnostic_setenv hinzugefügt:

#!/bin/csh -f
set args = ($*)
if ($#args == 1) then
   echo "export $args[1]="
   exit 0
endif

if ($#args == 2) then
   if ("$args[1]" =~ *csh*) then 
      echo "setenv $args[2]"
      exit 0
   else
      echo "export $args[1]=$args[2]"
      exit 0
   endif
endif

echo "setenv $args[2] $args[3]"

Und in ~ / .perl-homedir verwende ich:

eval `${HOME}/bin/agnostic_setenv $shell PERL_HOMEDIR 0`

Ein ähnliches Skript für agnostic_unsetenv:

#!/bin/csh -f
set args = ($*)
if ($#args == 1) then
   echo "export $args[1]"
   exit 0
endif

echo "unsetenv $args[2]"
exit 0
Kobi
quelle