Updating screen session environment variables to reflect new graphical login?
Solution 1
I have implemented a script to do this. You can get it here: https://github.com/DarwinAwardWinner/screen-sendenv
After putting screen-sendenv.py
into your $PATH
, you can use the following snippet in your .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
}
To use it, just run screen_pushenv
before you run screen -r
to reattach to your screen session. Then, after attaching with screen -r
, you can update the environment in your existing shells with screen_pullenv
. The tmux functions accomplish the same thing for tmux, another terminal multiplexer similar to screen.
Solution 2
You cannot start a shell script from the screen
session since it would inherit the old environment. You can however us a fifo to get the new environment variables into the old screen session. You can fill that fifo when you start your graphical session.
#!/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
Start that script in the background on login (it will only terminate when all variables are read from it).
Now you can read from the fifo, e.g. add this function to your .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
}
so that you can in your old screen
session
update_session
Solution 3
You can invoke the setenv
command to change environment variables in the screen process interactively, by using: Ctrl-A+:setenv
(Note the :
character to enter a screen command.) You will be prompted for the environment variable name and value.
Note that (as per other answers/comments) this affects the (parent) screen process and therefore newly-created screen sessions, but not your current screen session nor any existing screen sessions.
You can specify the environment variable name and value at the same time if you want: Ctrl-A+:setenv DISPLAY :100
. Will set the DISPLAY to ":100" for new screen sessions.
To remove an environment variable you can use 'unsetenv' - e.g. Ctrl-A+:unsetenv DISPLAY
Solution 4
This is probably a simpler solution (you decide). The important part being the alias that calls the savedisplay
function every time screen
command is run. The commands are not run automatically, hence can be put in ~/.bashrc
instead of something very specialized like ~/.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'
Solution 5
This thread is very old but the problem persists. I thought I'd post a slightly more robust version of the answer posted by @wecac. I put this into my .bashrc:
# Save X display-related environment variables for use in `screen` sessions.
savescreenenv() {
# Write a bash script to update the environment. The script is named for
# the host so that `screen` sessions on different hosts can have different
# environments.
mkdir -p ~/.screenenv
envfile=~/.screenenv/$(hostname)
# Any output within this loop is captured to the $envfile script.
for var in DISPLAY XAUTHORITY DBUS_SESSION_BUS_ADDRESS \
SESSION_MANAGER GPG_AGENT_INFO
do
# For each non-empty environment variable, write commands to:
# 1. Restore the environment variable
# 2. Set the environment variable in the current `screen` session.
if [ ! -z "${!var}" ]; then
echo "export $var='${!var}'"
echo "screen -X setenv $var '${!var}'"
fi
done > $envfile
}
# Restore environment set by `savescreenenv`. Run this command manually in
# each screen sub-terminal after disconnecting and re-connecting to `screen`.
updateenv() {
envfile=~/.screenenv/$(hostname)
if [ -f $envfile ]; then
. $envfile
fi
}
# Alias `screen` to save select environment variables first.
# Do not alias `screen` from within a screen session else old variables could
# be written to $envfile by accident.
unalias screen 2> /dev/null
if ! ${IN_SCREEN:-false}; then
alias screen='savescreenenv && IN_SCREEN=true screen'
fi
The trick is to remember to run updateenv
manually in each existing screen sub-terminal upon reconnecting. New sub-terminals will automatically get the correct environment if updateenv
was run once in at least one existing sub-terminal.
Ryan C. Thompson
Updated on September 17, 2022Comments
-
Ryan C. Thompson over 1 year
I use linux, and I like to do all my command-line work within a single screen session, so that I can restart my graphical login and such without losing my terminals. However, when I log out and back into my graphical session, this changes all my session environment variables, such as DBus sessions. This means that after logging in again, my screen session now has the old (and wrong) environment variables. So now when I try to start graphical programs from my screen session, at best they emit a warning about not being able to connect to the session bus. At worst, they fail to start completely.
So, what I'm looking for is a way to modify environment variables in a running instance of screen, so that all subsequently-created screen windows will inherit the new environment variables. Is there a way to do this?
-
Ryan C. Thompson about 14 yearsAha! I just paged through the whole screen manpage to find this:
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.
-
Boris Bukh over 12 yearsOne can invoke setenv using -X switch to screen. Alas, it works only on all subsequently forked shells, not on the current shell.
-
Ryan C. Thompson over 9 yearsNote that byobu now incorporates a solution for this for both screen and tmux.
-
-
quack quixote about 14 yearswouldn't you need to do this once per window in the running session to modify the window's main shell?
-
dmckee --- ex-moderator kitten about 14 yearsNice, though as ~quack says, you do need to update each shell independently.
-
Benjamin Bannier about 14 yearsRight, you need to do that in each shell in
screen
. AFAIKscreen
exposes no sockets or similar to communicate with running sessions from the outside. -
Benjamin Bannier about 14 years@dmckee but of course every new
screen
session already has the recent environment variables -
Ryan C. Thompson about 14 yearsI've decided to just accept this answer for now. If I ever get around to actually implementing this, I'll update. But for now, it's enough just to have warm fuzzy feeling of knowing that it's theoretically possible.
-
Benjamin Bannier over 12 yearsWow Ryan, that is a lot of code. What was wrong with the previously accepted answer (it was inspiring at least)?
-
Ryan C. Thompson over 12 yearsWell, I discovered that screen (and also tmux) have a "setenv" command that sets an environment variable for screen itself, not the shell in the current window of screen. So that means that after you use my script, all newly-created windows in that screen session will automatically get the new environment, without having to run the update script in every one of them. Of course, an update script could still be useful for updating existing shells, but you have to rewrite it not to read from a FIFO, but to query the screen/tmux session itself for the new values.
-
Ryan C. Thompson over 12 yearsYou can see how to pull variables into the current shell from the screen/tmux session here, in the
screen_update
andtmux_update
functions. I'll update my answer with a byobu-independent version of these. -
Ryan C. Thompson over 12 yearsAnyway, to directly answer your question about what was wrong, your answer doesn't quite answer the question, but rather answers a related question. You show how to update environment variables inside a shell running inside a screen session, but not how to update environment variables in the screen session itself (such that newly-spawned windows inherit the new values). I accepted it at the time because it was still a good solution, but I had always intended to eventually implement a real answer to my question as asked. So, nothing personal.
-
drizzd almost 7 yearsI had to add
sync
before. "$tempfile"
for this to work with home directories on NFS. -
Pablo Halpern over 3 yearsRight idea, but seems overly complicated. Why use a FIFO with a background process rather than writing a simple temp file? In fact, the temp file would be in the format of a shell script so, once written, all your
update_session
function would need to do is source the file. And you can re-use it for multiple shells within the same screen. Nevertheless, I'm going to borrow the idea. -
carlfriedrich over 2 yearsThis works perfectly, thanks a lot!
-
Pablo Halpern over 2 yearsThis works, but see my updated version based on the same concept.