Quelle est la meilleure façon indépendante de la distribution / shell pour définir les variables d'environnement?

31

La question dit tout. J'utilise actuellement Arch Linux et le zsh, mais j'aimerais une solution qui (au minimum) fonctionne à la fois sur les VT et dans les xterms et aussi (espérons-le, de préférence) continuera à fonctionner si je change de distributions ou de shells.

J'ai entendu des réponses extrêmement disparates à cette question dans différents documents de distributions. Ubuntu dit "utilisez .pam_environment". Je pense que dans Arch, ce qu'ils recommandent dépend de votre shell. Actuellement, je mets tout dans .profile et si un shell ne source pas cela pour une raison quelconque (par exemple bash si .bash_profile existe), je remplace cela en le sourcing manuellement. Mais il semble qu'il doit y avoir un meilleur moyen.

combattant
la source
2
Cela n'a rien à voir avec la distribution et tout à voir avec le shell. Je ne suis pas sûr qu'il existe un moyen portable de le faire, cependant.
Joseph R.
Hmm. Génial .
strugee

Réponses:

29

Il n'y a malheureusement aucun emplacement entièrement portable pour définir les variables d'environnement. Les deux fichiers qui se rapprochent le plus sont ~/.profile, qui est l'emplacement traditionnel et fonctionne dès le départ sur de nombreuses configurations, et ~/.pam_environment, une alternative moderne, courante mais limitée.

Que mettre ~/.pam_environment

Le fichier ~/.pam_environmentest lu par toutes les méthodes de connexion qui utilisent PAM et qui ont ce fichier activé. Cela couvre la plupart des systèmes Linux de nos jours.

Le principal avantage ~/.pam_environmentest que (lorsqu'il est activé), il est lu avant le démarrage du shell de l'utilisateur, il fonctionne donc quel que soit le type de session, le shell de connexion et d'autres complexités. Il fonctionne même pour les connexions non interactives telles que su -c somecommandet ssh somecommand.

La principale limitation ~/.pam_environmentest que vous ne pouvez y mettre que des affectations simples, pas une syntaxe de shell complexe. La syntaxe de ce fichier est la suivante.

  • Les fichiers sont analysés ligne par ligne.
  • Les espaces blancs de tête sont ignorés.
  • Vous pouvez éventuellement commencer des lignes avec exportet un seul espace (pas un onglet, allez comprendre).
  • Après cela, chaque ligne doit avoir la forme VAR=VALUEoù VAR se compose de lettres, de chiffres et de traits de soulignement.
  • # démarre un commentaire, il ne peut pas apparaître dans une valeur.
  • Si VALUE commence par 'ou "et contient une autre citation identique, alors VAR est défini sur la chaîne entre les guillemets (tout ce qui suit la deuxième citation est ignoré). Sinon, VAR est défini sur la chaîne après le =signe.
  • S'il n'y en a pas =, la variable est supprimée de l'environnement.

Donc, à la hausse, ~/.pam_environmentfonctionne dans un large éventail de circonstances. En revanche, vous ne pouvez pas avoir de paramètres dynamiques tels que baser la valeur d'une variable sur une autre variable (par exemple, ajouter un répertoire à PATH) ou utiliser la sortie d'une commande (par exemple, tester si un répertoire ou un programme est présent), et certains les caractères ( #'", nouvelle ligne) sont impossibles ou gênants à mettre dans la valeur.

Que mettre ~/.profile

Ce fichier doit avoir une syntaxe sh portable (POSIX). N'utilisez des extensions ksh ou bash (tableaux, [[ … ]]etc.) que si vous savez que votre système possède ces shells en tant que /bin/sh.

Ce fichier peut être lu par des scripts dans des applications automatisées, il ne doit donc pas appeler de programmes qui produisent une sortie ou un appel exec. Si vous souhaitez le faire sur les connexions en mode texte, faites-le uniquement pour les shells interactifs. Exemple:

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

Ceci est un exemple d'utilisation /bin/shcomme shell de connexion et de basculement vers votre shell préféré. Voir aussi comment utiliser bash comme shell de connexion lorsque mon administrateur système refuse de me laisser le changer

Quand n'est-il ~/.profilepas lu lors de la connexion non graphique?

Différents shells de connexion lisent différents fichiers.

Si votre shell de connexion est bash

Bash lit ~/.bash_loginou ~/.bash_profiles'ils existent à la place de ~/.profile. Bash ne lit pas non plus ~/.bashrcdans un shell de connexion même s'il est interactif. Pour ne plus jamais avoir à vous souvenir de ces bizarreries, créez un ~/.bash_profileavec les deux lignes suivantes:

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

Voir aussi Quels fichiers de configuration doivent être utilisés pour configurer les variables d'environnement avec bash?

Si votre shell de connexion est zsh

Zsh lit ~/.zprofileet ~/.zlogin, mais pas ~/.profile. Zsh a une syntaxe différente de sh, mais peut lire ~/.profileen mode d'émulation sh. Vous pouvez l'utiliser pour ~/.zprofile:

emulate sh -c '. ~/.profile'

Voir aussi Zsh ne frappant pas ~ / .profile

Si votre shell de connexion est un autre shell

Il n'y a pas grand-chose que vous puissiez faire là-bas, à part utiliser /bin/shcomme shell de connexion et votre shell préféré (comme le poisson) comme shell interactif uniquement. C'est ce que je fais avec zsh. Voir ci-dessus pour un exemple d'appel d'un autre shell à partir de ~/.profile.

Commandes à distance

Lors de l'appel d'une commande à distance sans passer par un shell interactif, tous les shells ne lisent pas un fichier de démarrage.

Ksh lit le fichier spécifié par la ENVvariable, si vous parvenez à le transmettre.

Bash lit ~/.bashrcs'il n'est pas interactif (!) Et son processus parent est appelé rshdou sshd. Ainsi , vous pouvez commencer votre ~/.bashrcavec

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

Zsh lit toujours ~/.zshenvquand il démarre. À utiliser avec prudence, car il est lu par chaque instance de zsh, même lorsqu'il s'agit d'un sous-shell où vous avez défini d'autres variables. Si zsh est votre shell de connexion et que vous souhaitez l'utiliser pour définir des variables uniquement pour les commandes distantes, utilisez un garde: définissez une variable dans ~/.profile, comme MY_ENVIRONMENT_HAS_BEEN_SET=yes, et vérifiez cette garde avant de lire ~/.profile.

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

Le cas des connexions graphiques

De nombreuses distributions, gestionnaires d'affichage et environnements de bureau s'arrangent pour s'exécuter ~/.profile, soit en les approvisionnant explicitement à partir des scripts de démarrage, soit en exécutant un shell de connexion.

Malheureusement, il n'y a pas de méthode générale pour gérer les combinaisons distro / DM / DE qui ~/.profilene sont pas lues.

Si vous utilisez une session traditionnelle démarrée par ~/.xsession, c'est l'endroit où vous devez définir vos variables d'environnement; faites-le par sourcing ~/.profile(ie . ~/.profile). Notez que dans certaines configurations, les scripts de démarrage de l'environnement de bureau seront à ~/.profilenouveau source .

Gilles, arrête de faire le mal
la source
qu'est-ce que ça case $- in *i*)fait?
qodeninja
2
@qodeninja Exécute les instructions suivantes (jusqu'à la correspondance ;;ou esac) si $-correspond au modèle *i*, c'est-à-dire si $-contient i, c'est-à-dire si le shell est interactif.
Gilles 'SO- arrête d'être méchant'
$-est une chaîne des options shell actuellement définies. (comme set -x). isignifie shell interactif.
Peter Cordes
Vous ne pouvez pas simplement source un fichier commun, par exemple ~/.config/env, même sans émulation?
Kevin Suttle
1
@ StéphaneChazelas C'est une vision puriste. Je garde ma .profileconformité avec des obus Bourne assez vieux, mais je reconnais que certaines personnes s'en moquent. Je n'ai rien contre les gens qui supposent que sh = bash pour leurs propres fichiers, je m'en soucie seulement s'ils publient un #!/bin/shscript qui utilise les fonctionnalités de bash.
Gilles 'SO- arrête d'être méchant'
4

Autant que je sache, il n'existe pas de norme agnostique de distribution et de shell pour définir les variables d'environnement.

La norme la plus courante et de facto semble être /etc/profileet ~/.profile. Le deuxième plus courant semble être /etc/environmentet ~/.pam_environment.

Il me semble que toute la documentation que je vous ai trouvée existe déjà. Je les énumère ici de toute façon pour les autres lecteurs.

  • Debian recommande /etc/profileet ~/.profile( lien ).
  • Ubuntu recommande /etc/environmentet ~/.pam_environment( lien ).
  • Arch Linux mentionne, entre autres, /etc/profileet /etc/environment( lien ).

Bonus: un texte interrogeant l'utilisation et / ou la mauvaise utilisation de /etc/environmentDebian ( lien , dernière mise à jour 2008).

lesmana
la source
Quel que soit le fichier que vous utilisez, vous rencontrerez toujours une syntaxe incompatible entre différents shells.
Joseph R.
1
@JosephR. la plupart des shells ne sont-ils pas rétrocompatibles avec sh? Tant que vous vous en tenez à POSIX, j'aurais pensé que vous
iriez
1
AFAIK vous ne pouvez pas assigner de variables dans cshet amis de la manière POSIX (vous avez besoin de quelque chose comme setou setenv)
Joseph R.
0

J'ai ajouté le script suivant ~ / bin / agnostic_setenv:

#!/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]"

Et dans ~ / .perl-homedir j'utilise:

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

Un script similaire pour 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
la source