Mise à jour des variables d'environnement de session d'écran pour refléter la nouvelle connexion graphique?

20

J'utilise Linux, et j'aime faire tout mon travail en ligne de commande dans une seule session d'écran, afin de pouvoir redémarrer ma connexion graphique et autres sans perdre mes terminaux. Cependant, lorsque je me déconnecte et me reconnecte à ma session graphique, cela modifie toutes mes variables d'environnement de session, telles que les sessions DBus. Cela signifie qu'après une nouvelle connexion, ma session d'écran a maintenant les anciennes (et mauvaises) variables d'environnement. Alors maintenant, lorsque j'essaie de démarrer des programmes graphiques à partir de ma session d'écran, ils émettent au mieux un avertissement indiquant qu'ils ne peuvent pas se connecter au bus de session. Au pire, ils ne démarrent pas complètement.

Donc, ce que je recherche, c'est un moyen de modifier les variables d'environnement dans une instance d'écran en cours d'exécution, afin que toutes les fenêtres d'écran créées par la suite héritent des nouvelles variables d'environnement. Y a-t-il un moyen de faire cela?

Ryan C. Thompson
la source
3
Ah! Je viens de parcourir la page de manuel de l'écran pour trouver ceci:setenv [var [string]] Set the environment variable var to value string. If only var is specified, the user will be prompted to enter a value. If no parameters are specified, the user will be prompted for both variable and value. The environment is inherited by all subsequently forked shells.
Ryan C. Thompson
On peut invoquer setenv en utilisant le commutateur -X à l'écran. Hélas, il ne fonctionne que sur tous les shells bifurqués par la suite, pas sur le shell actuel.
Boris Bukh
Notez que byobu intègre désormais une solution pour cela à la fois pour l'écran et pour tmux.
Ryan C. Thompson du

Réponses:

8

Vous ne pouvez pas démarrer un script shell à partir de la screensession car il hériterait de l'ancien environnement. Vous pouvez cependant nous contacter un fifo pour obtenir les nouvelles variables d'environnement dans l'ancienne session d'écran. Vous pouvez remplir ce fifo lorsque vous démarrez votre session graphique.

#!/bin/bash
FIFO=/tmp/your_variables
[ -e $FIFO ] && cat $FIFO > /dev/null || mkfifo $FIFO

# save number of variables that follow
NVARS=2
echo $NVARS > $FIFO
echo ENV1=sth1 > $FIFO
echo ENV2=sth2 > $FIFO

Démarrez ce script en arrière-plan lors de la connexion (il ne se terminera que lorsque toutes les variables en seront lues).

Vous pouvez maintenant lire à partir du fifo, par exemple, ajoutez cette fonction à votre .bashrc

update_session() {
  FIFO=/tmp/your_variables

  NVAR=$(cat $FIFO)
  for i in $(seq $NVAR); do
    export $(cat $FIFO)
  done
  #delete the pipe, or it will not work next time 
  rm $FIFO
}

afin que vous puissiez dans votre ancienne screensession

update_session
Benjamin Bannier
la source
n'auriez-vous pas besoin de le faire une fois par fenêtre dans la session en cours pour modifier le shell principal de la fenêtre?
Quack Quichote
Bien, comme le dit ~ quack, vous devez mettre à jour chaque shell indépendamment.
dmckee
À droite, vous devez le faire dans chaque shell screen. AFAIK screenn'expose aucun socket ou similaire pour communiquer avec des sessions en cours d'exécution de l'extérieur.
Benjamin Bannier
@dmckee mais bien sûr, chaque nouvelle screen session a déjà les variables d'environnement récentes
Benjamin Bannier
J'ai décidé d'accepter cette réponse pour l'instant. Si jamais je parviens à implémenter cela, je mettrai à jour. Mais pour l'instant, il suffit juste d'avoir une sensation floue et chaleureuse de savoir que c'est théoriquement possible.
Ryan C. Thompson,
2

J'ai implémenté un script pour ce faire. Vous pouvez l'obtenir ici: https://github.com/DarwinAwardWinner/screen-sendenv

Après l'avoir placé screen-sendenv.pydans votre $PATH, vous pouvez utiliser l'extrait de code suivant dans votre .bashrc:

VARS_TO_UPDATE="DISPLAY DBUS_SESSION_BUS_ADDRESS SESSION_MANAGER GPG_AGENT_INFO"
screen_pushenv () {
  screen-sendenv.py -t screen $VARS_TO_UPDATE
}
tmux_pushenv () {
  screen-sendenv.py -t tmux $VARS_TO_UPDATE
}
screen_pullenv () {
  tempfile=$(mktemp -q) && {
    for var in $VARS_TO_UPDATE; do
      screen sh -c "echo export $var=\$$var >> \"$tempfile\""
    done
    . "$tempfile"
    rm -f "$tempfile"
  }
}
tmux_pullenv () {
  for var in $VARS_TO_UPDATE; do
    expr="$(tmux showenv | grep "^$var=")"
    if [ -n "$expr" ]; then
      export "$expr"
    fi
  done
}

Pour l'utiliser, exécutez-le juste screen_pushenvavant de vous screen -rreconnecter à votre session d'écran. Ensuite, après avoir attaché avec screen -r, vous pouvez mettre à jour l'environnement dans vos shells existants avec screen_pullenv. Les fonctions tmux accomplissent la même chose pour tmux, un autre multiplexeur de terminal similaire à screen.

Ryan C. Thompson
la source
Wow Ryan, c'est beaucoup de code. Qu'est-ce qui n'allait pas avec la réponse précédemment acceptée (c'était inspirant au moins)?
Benjamin Bannier
1
Eh bien, j'ai découvert que screen (et aussi tmux) ont une commande "setenv" qui définit une variable d'environnement pour screen lui-même, pas le shell dans la fenêtre courante de screen. Cela signifie donc qu'après avoir utilisé mon script, toutes les fenêtres nouvellement créées dans cette session d'écran obtiendront automatiquement le nouvel environnement, sans avoir à exécuter le script de mise à jour dans chacune d'elles. Bien sûr, un script de mise à jour pourrait toujours être utile pour mettre à jour des shells existants, mais vous devez le réécrire non pas pour lire à partir d'un FIFO, mais pour interroger la session screen / tmux elle-même pour les nouvelles valeurs.
Ryan C. Thompson
Vous pouvez voir comment extraire des variables dans le shell courant à partir de la session screen / tmux ici , dans les fonctions screen_updateet tmux_update. Je mettrai à jour ma réponse avec une version indépendante de byobu.
Ryan C. Thompson du
1
Quoi qu'il en soit, pour répondre directement à votre question sur ce qui n'allait pas, votre réponse ne répond pas tout à fait à la question, mais répond plutôt à une question connexe. Vous montrez comment mettre à jour les variables d'environnement à l'intérieur d'un shell exécuté à l'intérieur d'une session d'écran, mais pas comment mettre à jour les variables d'environnement dans la session d'écran elle-même (de sorte que les fenêtres nouvellement créées héritent des nouvelles valeurs). Je l'ai acceptée à l'époque car c'était toujours une bonne solution, mais j'avais toujours eu l'intention de mettre en œuvre éventuellement une vraie réponse à ma question telle que posée . Donc, rien de personnel.
Ryan C. Thompson du
Hey Ryan, merci d'avoir répondu. Maintenant que vous avez mentionné, setenvje vois comment c'est mieux. Ce n'était pas évident d'après le code auquel vous avez lié. Merci encore!
Benjamin Bannier
2

Vous pouvez appeler la setenvcommande pour modifier les variables d'environnement dans le processus d'écran de manière interactive, en utilisant: Ctrl- A+ :setenv(Notez le :caractère pour entrer une commande d'écran.) Vous serez invité à entrer le nom et la valeur de la variable d'environnement.

Notez que (selon d'autres réponses / commentaires) cela affecte le processus d'écran (parent) et donc les sessions d'écran nouvellement créées, mais pas votre session d'écran actuelle ni aucune session d'écran existante.

Vous pouvez spécifier le nom et la valeur de la variable d'environnement en même temps si vous le souhaitez: Ctrl- A+ :setenv DISPLAY :100. Définira l'AFFICHAGE sur ": 100" pour les nouvelles sessions d'écran.

Pour supprimer une variable d'environnement, vous pouvez utiliser 'unsetenv' - par exemple Ctrl- A+:unsetenv DISPLAY

Mr Weasel
la source
0

C'est probablement une solution plus simple (vous décidez). La partie importante étant l'alias qui appelle la savedisplayfonction à chaque screenexécution de la commande. Les commandes ne sont pas exécutées automatiquement, elles peuvent donc être insérées à la ~/.bashrcplace de quelque chose de très spécialisé comme ~/.ssh/rc.

savedisplay() {
    # Write latest bash display to a file, This is used to 
    # update running bash sessions for a "screen -r"
    echo "export DISPLAY=$DISPLAY" > ~/.XDISPLAY
    echo "export XAUTHORITY=$XAUTHORITY" >> ~/.XDISPLAY
    # This will only update the environment for new windows
    screen -X setenv DISPLAY $DISPLAY
    screen -X setenv XAUTHORITY $XAUTHORITY
}

# run this to update env variable in a running session
updatedisplay() {
    source ~/.XDISPLAY 
}

alias screen='savedisplay && screen'
wecac
la source