I have this line in my .tmux.conf file.
bind-key q run "fish --interactive -c q"
The code for function q is written in fish. This is the code.
function q
set session (t ls | fzf)
set chosen (string split ":" $session)
t switch -t $chosen[1]
end
What q does is simple. Pipe the output from the output for t ls, which is tmux ls, into fzf. Then split the string by : and then switch tmux sessions.
When I run q normally as a command in fish, it works fine. The fzf ui shows up and I can switch sessions.
But when I use the keybinding I set. It lets me change sessions but an interactive window does not appear. It just switches sessions without letting me choose.
What I want is to be able to have an interactive menu when I use prefix-q. So that I can choose which session I want to switch to.
When tmux invokes your bind-key shell command, it does so without any tmux pane active. That is, it runs the shell detached from any tty, because a tmux command might switch panes, or create a new pane, or destroy one; so it runs in a void.
The right idea is use tmux bindings to control tmux, and shell bindings to run commands in the current shell instance, which may in turn talk to tmux. Try this (as a shell command, not in tmux.conf):
bind \cTb q
This is a shell binding. Now 'control-T' followed by 'b' will run the menu in whatever pane is active.
The problem is the command capture alters the stdin/stdout/stderr file descriptors that fzf is handed. Try forcing it to interact with the tty:
set session (t ls | fzf 2>/dev/tty)
Pressing C-b and [ puts tmux in copy mode, this lets you select and copy text in a manner similar to vi.
Could you please show me how to add a new key binding like C-j to do this?
I guess it would look like - bind -n C-j function-to-enter-copy-mode
But, I don't know what the function to enter vi copy mode is called. I think I just need the function name.
bind -n C-j copy-mode
Add this to the tmux configuration file and reload tmux config
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 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.
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"