I can create a new session inside a session using this command <leader> :new. We can change the name later using <leader> $. Is there a way to define the name of that session when we create it and can we change the default directory of new created window in that session ?
Thanks
From the man page:
new-session [-AdDEP] [-c start-directory] [-F format] [-n window-name] [-s session-name] [-t group-name] [-x width] [-y height] [shell-command] (alias: new) Create a new session with name session-name.
If I understand your question correctly, you are looking for the -s and -c options.
Related
Just like leader_key + C creates a new window inside a session. Is there a similar shortcut for creating a new session ?
Currently, I use leader_key + new
Why not just create a keybinding for that in your .tmux.conf?
These two settings let you create/kill a new session when pressing Prefix Shift+s or Prefix Shift+K respectively:
bind S command-prompt -p "New Session:" "new-session -A -s '%%'"
bind K confirm kill-session
Prefix Shift+s will open a command prompt in the status line, asking for a new session name. It will either create a new session with that name or attach to an already existing session by that name.
From inside tmux you can just do
ctrl+B
then write :new<enter>
There are no predefined shortcuts, the only native way to do it is :
Create session: tmux new -s session_name
Ctrl-B + d to detach
Return to your session: tmux attach-session -t session_name
The tmux paste-buffer command can specify a session using the -t option:
tmux paste-buffer -b buffer-name -t session-name:window
But tmux load-buffer has no -t option:
tmux load-buffer [-b buffer-name] path
If you pass something like session-name:buffer-name to the -b option, it simply treats "session-name:buffer-name" as the buffer name.
I want to load a buffer in a tmux session from outside the session, and if there's more than one session running I want to specify which one.
Is there a (clean) way to do this?
(I suppose that setting the $TMUX environment variable would be a solution, but (a) it's not exactly clean, and (b) I haven't figured out how to get the appropriate value for the desired session.)
Buffers are global and do not belong to a particular session so there is no way to specify a session to load-buffer. You can name the buffers whatever you want so you could use a form that includes the session name.
I daily use tmux (2.5) on my laptop to work, and my tmux sessions have a starting directory which is the working directory I started the tmux session from. Every pane/window I open start with this starting directory as working directory.
I can change this starting directory, and this change would apply to the whole session.
But if I want to work on a different project with several panes, I could start a new window, but every pane I would open in it would start with the session's starting directory : I would have to cd to the new location for each pane which isn't practical.
If I need to work on several project/directories simultaneously, I can start a new terminal session, then cd to the relevant directory/project and start a new tmux session. That's not complicated.
But if I want to do the same thing on a server through ssh, I'd need to either :
open a new ssh session.
either embed my remote tmux sessions in an other tmux session.
Neither sounds practical to me, I'd prefer a single tmux session on the remote machine.
I think it would be more convenient to being able to start new window with its own starting directory location that would apply to any new pane opened in it. Is there a way to achieve this?
Edit :
I already tried the -c parameter of tmux new-window command.
But it doesn't assign its starting directory to the window created this way, it only applies this custom starting directory to the first pane created.
Any new pane opened in this window then uses the session's starting directory as default working dir (and not the path passed to tmux new-window).
This question is very similar to: https://unix.stackexchange.com/questions/12032/create-new-window-with-current-directory-in-tmux
It depends on your tmux version but the -c parameter does do the trick but it does not remember the setting. There used to be a default-path setting but that has been removed in version 1.9 unfortunately.
For newer versions you will need to pass along the -c in all cases (you can use an alias if you manually execute that command) or if you use key bindings you need to rebind the split/new window keys.
bind '"' split-window -c "#{pane_current_path}"
bind % split-window -h -c "#{pane_current_path}"
bind c new-window -c "#{pane_current_path}"
To use a custom path instead of the current pane path, execute this command:
tmux setenv custom_path /home/whatever/some/path
Put this in your config:
bind '"' split-window -c "#{custom_path}"
bind % split-window -h -c "#{custom_path}"
bind c new-window -c "#{custom_path}"
Yes, it turns out the -c option to the new-window command is what you are looking for: https://unix.stackexchange.com/questions/12032/create-new-window-with-current-directory-in-tmux Also, this: https://unix.stackexchange.com/questions/101949/new-tmux-panes-go-to-the-same-directory-as-the-current-pane-new-tmux-windows-go
So either of tmux new-window -c $(pwd) or tmux new-window -c /path/to/dir inside your tmux session should do it.
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.
I am trying to figure out how to attach to a tmux session if a named tmux session exists, if not I want to create a new one with the given name.
Currently, I know of a few tmux commands which can partly achieve what I am looking for, but its not clear how to combine them together to get what I am looking for:
tmux attach attaches to an automatically existing session - but errors out if no session exists
tmux new creates a new session - but it does so every time, so I can't leave it in my .tmux.conf
tmux has-session tests whether a session exists - but I don't know how to stitch it together with the other commands
Thus, I would like to create a tmux script, so that this happens automatically, instead of having to manually create it everytime I need to log into a sessions.
How can I write a automatic script so as to create a new tmux session (if a given session name doesnt exist) or attach to a session name (if it exists)?
I figured it out (and had it pointed out to me).
tmux attach || tmux new
Alternately, you can add
new-session
to your .tmux.conf - that will create a default session on server start.
Then tmux attach will either attach to the current session (running server, that is), or create a new session (start the server, read the config file, issue the new-session command) and attach to that.
As pointed out in comments from Petr Viktorin, jkoelker and pjincz, you can use the following command to attach to mySession if it exists, and to create it if it doesn't:
tmux new -A -s mySession
From man tmux:
new-session[-AdDEP] [-cstart-directory] [-Fformat] [-nwindow-name] [-ssession-name] [-tgroup-name] [-xwidth] [-yheight] [shell-command]
(alias: new)
Create a new session with name session-name.
[...]
The -A flag makes new-session behave like attach-session if session-name already exists; in this case, -D behaves like -d to attach-session.
new-session has supported -A since tmux-1.8.
Adapting Alex's suggestion to include project based configuration upon startup, I started using the following:
# ~/bin/tmux-myproject shell script
# The Project name is also used as a session name (usually shorter)
PROJECT_NAME="myproject"
PROJECT_DIR="~/myproject"
tmux has-session -t $PROJECT_NAME 2>/dev/null
if [ "$?" -eq 1 ] ; then
echo "No Session found. Creating and configuring."
pushd $PROJECT_DIR
tmux new-session -d -s $PROJECT_NAME
tmux source-file ~/bin/tmux-${PROJECT_NAME}.conf
popd
else
echo "Session found. Connecting."
fi
tmux attach-session -t $PROJECT_NAME
where tmux-myproject.conf is my startup series of tmux commands to create my windows and panes, as well as start my editors.
Although I find rampion's answer is sufficient for using 1 session, this script lets you setup multiple sessions:
SESSIONS="work play"
function has-session {
tmux has-session -t $1 2>/dev/null
}
function except
{
if [ "$?" -eq 1 ] ; then
$1
fi
}
# Configure your sessions here
function session-work
{
tmux new-session -d -s work
tmux neww -k -t work:1
}
function session-play
{
tmux new-session -d -s play
tmux neww -k -t play:1
}
#
#MAIN
for x in $SESSIONS
do
echo $x
has-session $x
except session-$x
done
NOTE:
-k --> new-window will not be created if already exists
-d --> start session or window, but don't attach to it yet
-s --> name the session
-t --> specify a target location in the form session:window.pane
I use an alias to create a new session if needed, and attach to my default session if it already exists:
alias tmuxre='tmux new-session -t default || tmux new-session -s default'
I added this to my .login on my server.
The reason I do it this way is because I don't want to attach to the same actual session, I want a new session which uses the same group of windows.
This is also similar to running screen -xRR.
For those who want to do the same thing in fish:
tmux attach -t mysesh; or tmux new -s mysesh
(edit: A solution considering named sessions is mentioned at the end of this answer)
I came across this question when I was looking for a particular use-case, but couldn't find any solutions to it, so I'll add mine here:
Upon terminal-launch tmux should:
check whether there are any unattached sessions and use the first it can find (each session will be attached only once)
if there are no unattached sessions create a new one
After reading through the tmux man-pages and looking up arrays in bash I was able to come up with the following one-liner:
tmux attach -t ${$(tmux list-sessions -F '#{session_name}' -f '#{==:#{session_attached},0}')[1]} || tmux new
Explanation:
tmux attach -t $A:
attach to session with content of variable A (in our case the return value of the list-session command + array-index call)
tmux new:
create new session
together -> tmux attach -t $A || tmux new:
if tmux attach fails, create a new session
The next part (our $A) is finding an unattached session:
A = ${$B[1]}: return the second element in the list B (first one seems to always be an empty string)
B = tmux list-sessions -F '#{session_name}' -f '#{==:#{session_attached},0}'
tmux list-sessions: list all sessions
tmux list-sessions -F '#{session_name}: -F stands for format and -F '#{session_name}' tells tmux to only show the name of the session and nothing else when it outputs the list
tmux list-sessions -f '#{==:#{session_attached},0}': -f stands for filter and -f '#{==:#{session_attached},0}'tells tmux to show only those list-elements, where the session_attached-value is equal to 0
tmux list-sessions -F '#{session_name}' -f '#{==:#{session_attached},0}': both flags in combination will output only the session name and only for those elements of the list, where the session_attached-value is equal to 0 (=unattached sessions)
Example:
My application was for WSL, so I added it to the launch of my Ubuntu profile inside the settings.json of Windows Terminal:
"commandline": "C:\\Windows\\system32\\wsl.exe -d Ubuntu-22.04 tmux attach -t ${$(tmux list-sessions -F '#{session_name}' -f '#{==:#{session_attached},0}')[1]} || tmux new",
Edit:
If you have ([a-zA-Z]) named sessions you can sort the list to put those at the beginning:
tmux attach -t ${$(sort -n <<<"${$(tmux list-sessions -F '#{session_name}' -f '#{==:#{session_attached},0}')[*]}")[1]} || tmux new
If you add tmux new -s "primary" || at the beginning of the previous command it will try to create the session with the name "primary" and if it already exists it will only attach to it if it is still unattached, otherwise it will take another unattached session (prioritizing named over unnamed) or just create a new unnamed session if there are no unattached sessions left.
Caveat: each time you run this command and "primary" already exists it will output an error-message that it wasn't able to create a session called "primary" (only visible for a split second)
edit edit:
you can redirect those messages by using &> /dev/null:
(tmux new -s primary || tmux new -s secondary || tmux new -s tertiary) &> /dev/null || tmux attach -t ${$(sort -n <<<"${$(tmux list-sessions -F '#{session_name}' -f '#{==:#{session_attached},0}')[*]}")[1]} || tmux new"