The naive way to do this is not working. Try this:
Start a first tmux session.
$ export ENVIRONMENT="production"
$ tmux
You can then verify that inside the session ENVIRONMENT is production
Then, in a second terminal start another session
$ export ENVIRONMENT="staging"
$ tmux
Surprisingly in this session ENVIRONMENT is also production! This is very unintuitive!
What is going on here?
How can I achive this? I like all windows in a session to "inherit" the ENVIRONMENT variable.
The "simplest" solution is to create a new tmux server with the different environment.
$ ENVIRONMENT=production tmux -L prod-tmux
and
$ ENVIRONMENT=staging tmux -L staging-tmux
You'll always need to specify which socket, prod-tmux or staging-tmux, to use whenever you reconnect to an existing session.
The next solution would be to use one server, but modify the environment of each session in that server. Something like
$ tmux new-session -d -s production
$ tmux new-session -d -s staging
$ tmux set-environment -t production ENVIRONMENT production
$ tmux set-environment -t staging ENVIRONMENT staging
Note that ENVIRONMENT would not be set in the process running in the initial window for each session, but will be for any subsequent window created. (Unless the server inherited ENVIRONMENT when it first started.)
When you run tmux, it first looks for an existing server (either the default server, or the one specified by either the -L or -S options). If there is no server, one is started, and the server's environment is inherited from the current environment.
If there is a server, tmux simply requests the server to execute a tmux command (by default, new-session, or whatever command is specified by an argument to tmux) command, then exits. The environment of the tmux command itself isn't relevant, unless the requested command is documented to read from it (cf. set-environment).
The server manages a group of windows, each of which represents a process created by the server (not the tmux command itself). A session is just a logical group of windows, also managed by the server.
Newer versions of tmux seem to support this natively! I do devops support for multiple clients and wanted to set a separate bash history file for each client. The following works very well for me! It sets the working directory, to the client/project dir, and sets the bash history file path
tmux new -c ~/Documents/code/CLIENT/ -e HISTFILE=~/Documents/code/CLIENT/.bash_history -s CLIENT -d
Based on the excellent answer by #chepner we can solve this issue by adding aliases to define different tmux commands for different servers. For example we could append the following to ~/.bashrc.
# somewhere in ~/.bashrc
alias tmux-s1='tmux -L s1'
alias tmux-s2='tmux -L s2'
alias tmux-s3='tmux -L s3'
alias tmux-s4='tmux -L s4'
alias tmux-s5='tmux -L s5'
Now we can use tmux-s1, tmux-s2, etc... the same way we would normally use the tmux command except each variant will be associated with a different server. When we create a session for a server that has no active sessions then the current environment variables will be used to initialize the server. To reattach to the session we will need the alias for the server that the session was created with.
Example
$ export ENVIRONMENT="production"
$ tmux-s1 ls
no server running on /tmp/tmux-12345/s1
$ tmux-s1
############### now attached to session 0 on server s1 ################
$ echo $ENVIRONMENT
production
################### (ctrl+b,d) detach from session ####################
[detached (from session 0)]
$ tmux-s1 ls
0: 1 windows (created Sun Nov 17 18:13:18 2019) [80x20]
$ export ENVIRONMENT="staging"
$ tmux-s2 ls
no server running on /tmp/tmux-12345/s2
$ tmux-s2
############### now attached to session 0 on server s2 ################
$ echo $ENVIRONMENT
staging
################### (ctrl+b,d) detach from session ####################
[detached (from session 0)]
$ tmux-s2 ls
0: 1 windows (created Sun Nov 17 18:13:22 2019) [80x20]
Related
I want to run unshare, mount a few directories, and run a tmux session in the new mount namespace. Here is my setup
$ cat run
#!/bin/bash
mount --bind ~/a ~/b
tmux
$ unshare -r --mount ~/run
When I run this command, I get dropped into the tmux session but without the binding. What is more strange to me is that if I rerun the mount command in the tmux session and exit, the next time I run unshare -r --mount ~/run the binding is there!
I could get consistent behavior by always running the mount command in the tmux session but I would like to understand why the behavior depends on if the binding existed in a previous session.
Replacing tmux with /bin/bash to poke at the mounted directory shows that the binding always happens, as expected. Once running the mount command in tmux, all subsequent runs have the binding until I move ~/a. Then the problem is back.
I am now unable to reproduce my own problem. I suspect the solution was to power cycle. I do not think I had done so between installing tmux and running into this issue, so that may have been the root cause.
I have RStudio server installed on a remote aws server (ubuntu) and want to run several projects at the same time (one of which takes lots of time to finish). On Windows there is a simple GUI solution like 'Open Project in New Window'. Is there something similar for rstudio server?
Simple question, but failed to find a solution except this related question for Macs, which offers
Run multiple rstudio sessions using projects
but how?
While running batch scripts is certainly a good option, it's not the only solution. Sometimes you may still want interactive use in different sessions rather than having to do everything as batch scripts.
Nothing stops you from running multiple instances of RStudio server on your Ubuntu server on different ports. (I find this particularly easy to do by launching RStudio through docker, as outlined here. Because an instance will keep running even when you close the browser window, you can easily launch several instances and switch between them. You'll just have to login again when you switch.
Unfortunately, RStudio-server still prevents you having multiple instances open in the browser at the same time (see the help forum). This is not a big issue as you just have to log in again, but you can work around it by using different browsers.
EDIT: Multiple instances are fine, as long as they are not on the same browser, same browser-user AND on the same IP address. e.g. a session on 127.0.0.1 and another on 0.0.0.0 would be fine. More importantly, the instances keep on running even if they are not 'open', so this really isn't a problem. The only thing to note about this is you would have to log back in to access the instance.
As for projects, you'll see you can switch between projects using the 'projects' button on the top right, but while this will preserve your other sessions I do not think the it actually supports simultaneous code execution. You need multiple instances of the R environment running to actually do that.
UPDATE 2020 Okay, it's now 2020 and there's lots of ways to do this.
For running scripts or functions in a new R environment, check out:
the callr package
The RStudio jobs panel
Run new R sessions or scripts from one or more terminal sessions in the RStudio terminal panel
Log out and log in to the RStudio-server as a different user (requires multiple users to be set up in the container, obviously not a good workflow for a single user but just noting that many different users can access the same RStudio server instance no problem.
Of course, spinning up multiple docker sessions on different ports is still a good option as well. Note that many of the ways listed above still do not allow you to restart the main R session, which prevents you from reloading installed packages, switching between projects, etc, which is clearly not ideal. I think it would be fantastic if switching between projects in an RStudio (server) session would allow jobs in the previously active project to keep running in the background, but have no idea if that's in the cards for the open source version.
Often you don't need several instances of Rstudio - in this case just save your code in .R file and launch it using ubuntu command prompt (maybe using screen)
Rscript script.R
That will launch a separate R session which will do the work without freezing your Rstudio. You can pass arguments too, for example
# script.R -
args <- commandArgs(trailingOnly = TRUE)
if (length(args) == 0) {
start = '2015-08-01'
} else {
start = args[1]
}
console -
Rscript script.R 2015-11-01
I think you need R Studio Server Pro to be able to log in with multiple users/sessions.
You can see the comparison table below for reference.
https://www.rstudio.com/products/rstudio-server-pro/
Installing another instance of rstudio server is less than ideal.
Linux server admins, fear not. You just need root access or a kind admin.
Create a group to use: groupadd Rwarrior
Create an additional user with same home directory as your primary Rstudio login:
useradd -d /home/user1 user2
Add primary and new user into Rwarrior group:
gpasswd -a user2 Rwarrior
gpasswd -a user1 Rwarrior
Take care of the permissions for your primary home directory:
cd /home
chown -R user1:Rwarrior /home/user1
chmod -R 770 /home/user1
chmod g+s /home/user1
Set password for the new user:
passwd user2
Open a new browser window in incognito/private browsing mode and login to Rstudio with the new user you created. Enjoy.
I run multiple RStudio servers by isolating them in Singularity instances. Download the Singularity image with the command singularity pull shub://nickjer/singularity-rstudio
I use two scripts:
run-rserver.sh:
Find a free port
#!/bin/env bash
set -ue
thisdir="$(dirname "${BASH_SOURCE[0]}")"
# Return 0 if the port $1 is free, else return 1
is_port_free(){
port="$1"
set +e
netstat -an |
grep --color=none "^tcp.*LISTEN\s*$" | \
awk '{gsub("^.*:","",$4);print $4}' | \
grep -q "^$port\$"
r="$?"
set -e
if [ "$r" = 0 ]; then return 1; else return 0; fi
}
# Find a free port
find_free_port(){
local lower_port="$1"
local upper_port="$2"
for ((port=lower_port; port <= upper_port; port++)); do
if is_port_free "$port"; then r=free; else r=used; fi
if [ "$r" = "used" -a "$port" = "$upper_port" ]; then
echo "Ports $lower_port to $upper_port are all in use" >&2
exit 1
fi
if [ "$r" = "free" ]; then break; fi
done
echo $port
}
port=$(find_free_port 8080 8200)
echo "Access RStudio Server on http://localhost:$port" >&2
"$thisdir/cexec" \
rserver \
--www-address 127.0.0.1 \
--www-port $port
cexec:
Create a dedicated config directory for each instance
Create a dedicated temporary directory for each instance
Use the singularity instance mechanism to avoid that forked R sessions are adopted by PID 1 and stay around after the rserver has shut down. Instead, they become children of the Singularity instance and are killed when that shuts down.
Map the current directory to the directory /data inside the container and set that as home folder (this step might not be nessecary if you don't care about reproducible paths on every machine)
#!/usr/bin/env bash
# Execute a command in the container
set -ue
if [ "${1-}" = "--help" ]; then
echo <<EOF
Usage: cexec command [args...]
Execute `command` in the container. This script starts the Singularity
container and executes the given command therein. The project root is mapped
to the folder `/data` inside the container. Moreover, a temporary directory
is provided at `/tmp` that is removed after the end of the script.
EOF
exit 0
fi
thisdir="$(dirname "${BASH_SOURCE[0]}")"
container="rserver_200403.sif"
# Create a temporary directory
tmpdir="$(mktemp -d -t cexec-XXXXXXXX)"
# We delete this directory afterwards, so its important that $tmpdir
# really has the path to an empty, temporary dir, and nothing else!
# (for example empty string or home dir)
if [[ ! "$tmpdir" || ! -d "$tmpdir" ]]; then
echo "Error: Could not create temp dir $tmpdir"
exit 1
fi
# check if temp dir is empty (this might be superfluous, see
# https://codereview.stackexchange.com/questions/238439)
tmpcontent="$(ls -A "$tmpdir")"
if [ ! -z "$tmpcontent" ]; then
echo "Error: Temp dir '$tmpdir' is not empty"
exit 1
fi
# Start Singularity instance
instancename="$(basename "$tmpdir")"
# Maybe also superfluous (like above)
rundir="$(readlink -f "$thisdir/.run/$instancename")"
if [ -e "$rundir" ]; then
echo "Error: Runtime directory '$rundir' exists already!" >&2
exit 1
fi
mkdir -p "$rundir"
singularity instance start \
--contain \
-W "$tmpdir" \
-H "$thisdir:/data" \
-B "$rundir:/data/.rstudio" \
-B "$thisdir/.rstudio/monitored/user-settings:/data/.rstudio/monitored/user-settings" \
"$container" \
"$instancename"
# Delete the temporary directory after the end of the script
trap "singularity instance stop '$instancename'; rm -rf '$tmpdir'; rm -rf '$rundir'" EXIT
singularity exec \
--pwd "/data" \
"instance://$instancename" \
"$#"
I am trying to find a nice way to restore the SSH agent when I reconnect a disconnected tmux session.
The cause seems to be that the SSH agent session changes but the environment variable from the tmux session is not updated.
How can I automate this, before attaching the session itself? Because the session I am attaching to does not always have a bash prompt, so I cannot afford to type something inside it. It has to be something to run before creating or attaching the tmux session.
An example of the code I'm running is at https://gist.github.com/ssbarnea/8646491 -- a small ssh wrapper that is using tmux to create persistem ssh connections. This works quite well, but sometimes the ssh agent stops working so I am no longer able to use it to connect to other hosts.
There's an excellent gist by Martijn Vermaat, which addresses your problem in great depth, although it is intended for screen users, so I'm adjusting it for tmux here.
To summarize:
create ~/.ssh/rc if it doesn't exist yet, and add the following content:
#!/bin/bash
# Fix SSH auth socket location so agent forwarding works with tmux.
if test "$SSH_AUTH_SOCK" ; then
ln -sf $SSH_AUTH_SOCK ~/.ssh/ssh_auth_sock
fi
Make it work in tmux, add this to your ~/.tmux.conf:
# fix ssh agent when tmux is detached
setenv -g SSH_AUTH_SOCK $HOME/.ssh/ssh_auth_sock
Extra work is required if you want to enable X11 forwarding, see the gist.
While tmux updates SSH variables by default, there is no need to
change/add socket path
change the SSH_AUTH_SOCKET variable
I like the solution by Chris Down which I changed to add function
fixssh() {
eval $(tmux show-env \
|sed -n 's/^\(SSH_[^=]*\)=\(.*\)/export \1="\2"/p')
}
into ~/.bashrc. Call fixssh after attaching session or before ssh/scp/rsync.
Newer versions of tmux support -s option for show-env, so only
eval $(tmux show-env -s |grep '^SSH_')
is possible.
Here's what I use for updating SSH_AUTH_SOCK inside a tmux window (based on Hans Ginzel's script):
alias fixssh='eval $(tmux showenv -s SSH_AUTH_SOCK)'
Or for tmux that does not have showenv -s:
alias fixssh='export $(tmux showenv SSH_AUTH_SOCK)'
Here is my solution which includes both approaches, and does not require extra typing when I reconnect to tmux session
alias ssh='[ -n "$TMUX" ] && eval $(tmux showenv -s SSH_AUTH_SOCK); /usr/bin/ssh'
There are lots of good answers here. But there are cases where tmux show-environment doesn't see SSH_AUTH_SOCK. In that case you can use find to locate it explicitly.
export SSH_AUTH_SOCK=$(find /tmp -path '*/ssh-*' -name 'agent*' -uid $(id -u) 2>/dev/null | tail -n1)
That's long and complicated, so I'll break it down...
01 export SSH_AUTH_SOCK=$(
02 find /tmp \
03 -path '*/ssh-*'
04 -name 'agent*'
05 -uid $(id -u)
06 2>/dev/null
07 | tail -n1
08 )
export the SSH_AUTH_SOCK environment variable set to the output of the $() command substitution
find files starting in /tmp
limit results to only those with /ssh- in the path
limit results to only those whose name begins with agent
limit results to only those with a user id matching the current user
silence all (permissions, etc.) errors
take only the last result if there are multiple
You may be able to leave off 6 & 7 if you know that there will only be 1 result and you don't care about stderr garbage.
I use a variation of the previous answers:
eval "export $(tmux show-environment -g SSH_AUTH_SOCK)"
assuming that you did the ssh agent started from the outer environment. Same goes for other environment variables such as DISPLAY.
I prefer to avoid configuring TMUX (etc) and keep everything purely in ~/.ssh/. On the remote system:
Create ~/.ssh/rc:
#!/bin/bash
# Fix SSH auth socket location so agent forwarding works within tmux
if test "$SSH_AUTH_SOCK" ; then
ln -sf $SSH_AUTH_SOCK ~/.ssh/ssh_auth_sock
fi
Add following to ~/.ssh/config so it no longer relies on $SSH_AUTH_SOCK, which goes stale in detached terminals:
Host *
IdentityAgent ~/.ssh/ssh_auth_sock
Known limitations
ssh-add doesn't use ~/.ssh/config and so cannot communicate with ssh-agent. Commands like ssh-add -l produce errors, even though ssh user#host works fine, as does updating git remotes which are accessed via SSH.
I may have worked out a solution that is fully encapsulated in the ~/.tmux.conf configuration file. It is a different approach than modifying the ~/.bash_profile and ~/.ssh/rc.
Solution only using ~/.tmux.conf
Just cut and paste the following code into your ~/.tmux.conf
# ~/.tmux.conf
# SSH agent forwarding
#
# Ensure that SSH-Agent forwarding will work when re-attaching to the tmux
# session from a different SSH connection (after a dropped connection).
# This code will run upon tmux create, tmux attach, or config reload.
#
# If there is an SSH_AUTH_SOCK originally defined:
# 1) Remove all SSH related env var names from update-environment.
# Without this, setenv cannot override variables such as SSH_AUTH_SOCK.
# Verify update-environment with: tmux show-option -g update-environment
# 2) Force-set SSH_AUTH_SOCK to be a known location
# /tmp/ssh_auth_sock_tmux
# 3) Force-create a link of the first found ssh-agent socket at the known location
if-shell '[ -n $SSH_AUTH_SOCK ]' " \
set-option -sg update-environment \"DISPLAY WINDOWID XAUTHORITY\"; \
setenv -g SSH_AUTH_SOCK /tmp/ssh_auth_sock_tmux; \
run-shell \"ln -sf $(find /tmp/ssh-* -type s -readable | head -n 1) /tmp/ssh_auth_sock_tmux\" \
"
Caveat
The above solution along with the other solutions are susceptible to a race condition when initiating multiple connections to the same machine. Consider this:
Client 1 Connect: SSH to machineX, start/attach tmux (writes ssh_auth_sock link)
Client 2 Connect: SSH to machineX, start/attach tmux (overwrites ssh_auth_sock link)
Client 2 Disconnect: Client 1 is left with a stale ssh_auth_sock link, thus breaking ssh-agent
However, this solution is slightly more resilient because it only overwrites the ssh_auth_sock link upon tmux start/attach, instead of upon initialization of a bash shell ~/.bash_profile or ssh connection ~/.ssh/rc
To cover this last race condition, one may add a key binding to reload the tmux configuration with a (Ctrl-b r) key sequence.
# ~/.tmux.conf
# reload config file
bind r source-file ~/.tmux.conf
From within an active tmux session, executing this sequence when the ssh_auth_sock link goes stale will refresh the ssh-agent connection.
In case other fish shell users are wondering how to deal with this when using fish (as well as for my future self!). In my fish_prompt I added a call to the following function:
function _update_tmux_ssh
if set -q TMUX
eval (tmux show-environment SSH_AUTH_SOCK | sed 's/\=/ /' | sed 's/^/set /')
end
end
I suppose that more advanced *nix users would know how to replace sed with something better, but this works (tmux 3.0, fish 3.1).
Following up on #pymkin's answer above, add the following, which worked with tmux 3.2a on macOS 11.5.3:
To ~/.tmux.conf:
# first, unset update-environment[SSH_AUTH_SOCK] (idx 3), to prevent
# the client overriding the global value
set-option -g -u update-environment[3]
# And set the global value to our static symlink'd path:
set-environment -g SSH_AUTH_SOCK $HOME/.ssh/ssh_auth_sock
To ~/.ssh/rc:
#!/bin/sh
# On SSH connection, create stable auth socket path for Tmux usage
if test "$SSH_AUTH_SOCK"; then
ln -sf "$SSH_AUTH_SOCK" ~/.ssh/ssh_auth_sock
fi
What's going on? Tmux has the semi-helpful update-environment variable/feature to pick up certain environment variables when a client connects. I.e. when you do tmux new or tmux attach, it'll update the tmux environment from when you ran those commands. That's nice for new shells or commands you run inside tmux afterwards, but it doesn't help those shells you've started prior to the latest attach. To solve this, you could use some of the other answers here to have existing shells pick up this updated environment, but that's not the route I chose.
Instead, we're setting a static value for SSH_AUTH_SOCK inside tmux, which will be ~/.ssh/ssh_auth_sock. All shells inside tmux would pick that up, and never have to be updated later. Then, we configure ssh so that, upon connection, it updates that static path with a symlink to the latest real socket that ssh knows.
The missing piece from #pymkin's answer is that Tmux will have the session value override the global value, so doing set-environment -g isn't sufficient; it gets squashed whenever you re-attach. You also have to also tell tmux not to update SSH_AUTH_SOCK in the session environment, so that the global value can make it through. That's what the set-option -g -u is about.
After coming across so many suggestions, I finally figured out a solution that enables TMUX update the stale ssh agent after being attached. Basically, both the zshrc files on the local and remote machines need to be modified.
Insert the following codes into the local zshrc, which is based on this reference.
export SSH_AUTH_SOCK=~/.ssh/ssh-agent.$(hostname).sock
ssh-add -l 2>/dev/null >/dev/null
# The error of executing ssh-add command denotes a valid agent does not
# exist.
if [ $? -ge 1 ]; then
# remove the socket if it exists
if [ -S "${SSH_AUTH_SOCK}" ]; then
rm "${SSH_AUTH_SOCK}"
fi
ssh-agent -a "${SSH_AUTH_SOCK}" >/dev/null
# one week life time
ssh-add -t 1W path-to-private-rsa-file
fi
Insert the following code into the remote zshrc, where the tmux session will be attached.
alias fixssh='eval $(tmux showenv -s SSH_AUTH_SOCK)'
Then ssh into the remote machine. The -A option is necessary.
ssh -A username#hostname
Attach the TMUX session. Check the TMUX evironment variables
# run this command in the shell
tmux showenv -s
# or run this command after prefix CTRL+A or CTRL+B
:show-environment
Run fixssh in the previously existed panes to update the ssh agent. If a new pane is created, it will automatically get the new ssh-agent.
Here's another simple Bash solution, using PROMPT_COMMAND to update the SSH_* vars inside tmux before each prompt is generated. The downside to this solution is that it doesn't take effect in existing shells until a new prompt is generated, because PROMPT_COMMAND is only run before creating new prompts.
Just add this to your ~/.bashrc:
update_tmux_env () {
# Only run for shells inside a tmux session.
if [[ -n "$TMUX" ]]; then
eval $(tmux show-env -s | grep '^SSH_')
fi
}
export PROMPT_COMMAND=update_tmux_env
Here's a new fix to an old problem: I think it's simpler than the other fixes and there's no need to make a static socket or mess with the shell prompt or make a separate command you have to remember to run.
I added this code added to my .bashrc file:
if [[ -n $TMUX ]]; then
_fix_ssh_agent_in_tmux () { if [[ ! -S $SSH_AUTH_SOCK ]]; then eval export $(tmux show-env | grep SSH_AUTH_SOCK); fi }
ssh () { _fix_ssh_agent_in_tmux; command ssh $#; }
scp () { _fix_ssh_agent_in_tmux; command scp $#; }
git () { _fix_ssh_agent_in_tmux; command git $#; }
rsync () { _fix_ssh_agent_in_tmux; command rsync $#; }
fi
If the shell is running within tmux, it redefines 'ssh' and its ilk to bash functions which test and fix SSH_AUTH_SOCK before actually running the real commands.
Note that tmux show-env -g also returns a value for SSH_AUTH_SOCK but that one is stale, I assume it's from whenever the tmux server started. The command above queries the current tmux session's environment which seems to be correct.
I'm using tmux 2.6 (ships with with Ubuntu 18.04) and it seems to work well.
I work in a situation where I have multiple projects and within each are many scripts that make use of environment variables set to values specific to that project.
What i'd like to do is use a separate tmux session for each project and set the variables so that they are set for all windows in that session.
I tried to use the set-environment option which works using the -g option but then sets the variable for all sessions connected to that server.
Without the -g option I see its set when using show-environment but can't access the variable in the shell.
Has anyone come up with a way of fixing this?
Using tmux 1.8 and tcsh
I figured out a way to do this. I'm using tmux 2.5.
Background
In the tmux man page, it states that there are two groups of environment variables: global and per-session. When you create a new tmux session, it will merge the two groups together and that becomes the set of environment variables available within the session. If the environment variables get added to the global group, it appears that they get shared between all open sessions. You want to add them to the per-session group.
Do this
Step 1: Create a tmux session.
tmux new-session -s one
Step 2: Add an environment variable to the per-session group.
tmux setenv FOO foo-one
This adds the environment variable to per-session set of environment variables. If you type tmux showenv, you'll see it in the output. However, it isn't in the environment of the current session. Typing echo $FOO won't give you anything. There's probably a better way to do this, but I found it easiest to just export it manually:
export FOO='foo-one'
Step 3: Create new windows/panes
Now, every time you create a new window or pane in the current session, tmux will grab the FOO environment variable from the per-session group.
Automating it
I use bash scripts to automatically create tmux sessions that make use of these environment variables. Here's an example of how I might automate the above:
#!/bin/bash
BAR='foo-one'
tmux new-session -s one \; \
setenv FOO $BAR \; \
send-keys -t 0 "export FOO="$BAR C-m \; \
split-window -v \; \
send-keys -t 0 'echo $FOO' C-m \; \
send-keys -t 1 'echo $FOO' C-m
You can access tmux (local) environment variables for each session, while in a session, with the command:
bash> tmux show-environment
If you add the -g parameter you get the environment for all sessions, i.e. the global environment. The local environments are NOT the same as the global environment. The previous command prints the entire local environment, but you can also look at just one variable:
bash> tmux show-environment variable_name
variable_name=value
To get the value, you could use some 'sed' magic or use 'export' on a single variable, or you can even 'export' the entire environment to your shell. Below are the 3 approaches.
bash> tmux show-environment variable_name | sed "s:^.*=::"
value
bash> eval "export $(tmux show-environment variable_name)"
bash> echo $variable_name
value
bash> for var in $(tmux show-environment | grep -v "^-"); do eval "export $var"; done;
bash> echo $variable_name
value
If needed, you can just add the -g parameter after the show-environment command if you want to access the global environment.
I've done a simple
export MY_VAR="some value"
before I start the tmux session, which gives me access to MY_VAR from all windows inside that session.
Version 3.2 of tmux will support a -e option for the new-session command for altering the local environment directly.
In the mean time, you can use this to run a new tmux session with a particular environment available and up to date (or one of the other solutions mentioned):
tmux new-session 'export MY_VAR=value; exec bash'
The problem with tmux is that when you first run it, the tmux server is created and it inherits the environment that is available at this time of creation. This is called the global environment. When you run tmux again and create a new session, the tmux server still holds its copy of the environment. But this copy is the "old" environment that the server learned about when it was created, i.e. the global environment.
About the tmux commands that work with the tmux environment:
set update-environment MY_VAR: this will tell tmux to take the MY_VAR variable from the global environment and make it a session environment, i.e. a local environment (listed by the show-environment command). Then, the session will be able to change the value of this variable without affecting the global environment.
set-environment MY_VAR value: This will create (or change) a variable in the local environment of the session.
set-environment -g MY_VAR value: This will create (or change) a variable in the global environment.
Also, note that when you run tmux and tmux calls bash (or another shell), bash will have a copy of the server's (global) environment. Even if you change an environment variable before calling tmux, creating a new session will be oblivious of the changes. If you add a tmux command in a conf file and run tmux e.g. with tmux source-file tmux-session.conf, any variable you mention in the conf will be evaluated in the context of the global environments the tmux server knows about and not the in the context from where you run the tmux command. So, in order to make a new session see the new value of the variable, you have to call tmux in a way that passes the new value of the env variable directly to it. This is what the solutions here try to do. This is also what the new -e option will allow you to do.
I approached this a little differently, assuming I had separate initialization scripts for each environment.
Using tmux v3.0a.
The spec:
When I invoke tmux I want it to load up a specific environment for that session.
For each window within the tmux session I want that same environment session replicated.
I also want to be able to invoke subsequent tmux sessions with different environments and each window invocation should load that environment. (just like the first session) And subsequent sessions should not interfere with prior sessions.
I have shell scripts to initialize each of my environments.
So how can I associate a shell script with a session and have all window invocations use that shell script?
Simple Solution:
Found a simple solution here: How to start two tmux sessions with different environments?
With my original solution I ran into an issue with the tmux global environment. When I ran multiple sessions, whichever one ran first set the global environment. Then I would need to close other tmux sessions before I ran new sessions.
A better solution is to set up a separate tmux server for each environment.
Use the -L flag to tmux from within a shell that already has the environment defined you want.
Shell environment A: tmux -L environA
Shell environment B: tmux -L environB
Name your environments any way you want. Set up some aliases for each environment? Or you can test environment variables to determine which tmux server you want to use. Each tmux named server will keep its environment separate.
Then there is no need to set bash startup files, etc. as I had described in my original solution.
Example
In my case I'm starting a tmux session per project within a bash script and I needed to activate a relevant virtual environment for that session, including any newly opened tabs. To do so, I added the following virtual environment activation code to the ~/.bashrc:
if [ -n "$VIRTUAL_ENV" ]; then
source $VIRTUAL_ENV/bin/activate;
fi
However if I need to set foo environment for Session_1 and bar environment for Session_2, the VIRTUAL_ENV variable is globally set to bar after creating Session_2, so any newly opened tabs in Session_1 erroneously ends up in bar environment.
Solution
original HOWTO (commit).
Add the following in your ~/.profile (or ~/.bashrc):
# For Tmux VirtualEnv support
tmux_get_var(){
local key=$1
[[ -n "$TMUX" ]] && tmux showenv | awk -F= -v key="$key" '$1==key {print $2}'
}
# activate the virtual environment if it is declared
venv=$(tmux_get_var "VIRTUAL_ENV")
if [ -n "$venv" ]; then
source $venv/bin/activate;
fi
Set the VIRTUAL_ENV variable for the target session:
tmux setenv -t ${SESSION_NAME} 'VIRTUAL_ENV' /path/to/virtualenv/
Setting it for current session is quite easy: Ctr-b: to open tmux command prompt and enter setenv FOO foo. This will not apply for existing windows -- but there you can use export $(tmux show-env FOO).
For new sessions this pattern might be useful:
tmux new -s session
Ctr-b : set-env FOO foo -- set FOO=foo for the session
Ctr-b c -- create new, second window ($FOO is set here)
Ctr-b l -- go to old, first window
exit the first window
all windows now have FOO=foo
Tested with Tmux 1.8.
In tmux I only have 2 groups, as opposed to the expected 5:
$ groups
username sudo staff website1 website2
$ tmux
$ groups
username sudo
Why is this and how do I fix it?
Perhaps your tmux server was started before you were added to the additional groups. The server process and any processes which it starts will only have the permissions that were in place when the server was started.
You can fix this by closing all sessions and starting a new server. Once you've quit any programs that you care about which are running inside tmux sessions you can use tmux kill-server to ensure that the old server process is ended. Then when you run tmux again it will automatically start a new server which should have all of your current permissions.