tmux: attach to existing session in new grouped session - bash

I want to start tmux when opening a new terminal window via shortcut (ALT+F1).
tmux should start a new session when there is no session that I can attach to.
If there is an existing session, but I am not attached to it, simply attach.
If there is an existing session and I am already attached to it (i.e., I am opening a 2nd terminal window), I want to attach to the same session and be able to work on another window.
Currently, I am using the following script called tmux-init for the first two points:
#!/bin/sh
# Attach TMUX, or else open new session
if [[ -x "$(command -v tmux)" ]] && [[ -n "${DISPLAY}" ]] && [[ -z "${TMUX}" ]]; then
tmux attach || tmux >/dev/null 2>&1
fi
This automatically attaches to my existing session, or creates a new one when it does not exist.
However, I want to be able to open multiple windows and work on all of them at the same time.
Currently, all of the opened windows would be attached to the same session and mirror everything. The idea was to use tmux groups (tmux new-session -t 0), but my knowledge of bash scripting and tmux is limited. Here is what I currently have (tmux-init-2):
#!/bin/sh
tmuxtest=$(tmux ls | grep attached | grep "group 0")
if [[ ! -z "$tmuxtest" ]]
then
tmux new-session -t 0
tmux set-option destroy-unattached on
tmux new-window
else
tmux-init
fi
This works sometimes, sometimes it does not open a new window, sometimes it does not destroy the grouped session on detach... I can't seem to find a pattern. In most cases, the new window opens after I detach from the session. It seems that I should pass the options to tmux in a different way - but I have not found a way to create a new session and set options for that session immediately. Is there a better way to do it?

Related

Display welcome message in new tmux session

In a bash script, a new tmux session is started, several processes are launched in separate panes, then the session is attached to the current terminal. I would like to display a short message that gives a few helpful hints how to navigate panes, exit the session etc.
I tried to just echo, but that is not executed inside the session. Is there a good approach how to do this?
Edit: my use case is to have everything contained in a repository. I want to avoid adding config to dotfiles or anything in the user's home dir.
There are a few ways you could print your message perhaps:
Make tmux enter copy mode with some output, for example: tmux new \; run 'echo hello'
Run a script in a new window that prints the output: tmux neww 'echo hello; sleep 5'
Make one of your panes (if your tmux is new enough) open a popup: tmux new 'tmux popup -KER "echo hello; sleep 5"; exec $SHELL"
You can check to see if there are tmux specific environment variables set in your .bashrc and print a message if they exist
eg. in your .bashrc
if [ ! -z "$TMUX" ]; then
echo "Your message"
fi

Solution for using iTerm2 'shell integration' and screen (over ssh)

So when i ssh into a remote server i use 'screen -R myscreen' to prevent any running scripts/processes from being interrupted when the ssh connection disconnects, for whatever reason (bad wifi, etc).
However, when starting screen, iTerm2's shell integration doesn't work anymore.
Is there any workaround for this?
fyi the solution i found is:
instead of 'screen' use 'tmux', by executing tmux -CC to open a tmux session (and using tmux -CC attach to re-attach after a disconnection.)
This is also described here.
To make iTerm2 shell integration work in tmux, modify ~/.iterm2_shell_integration.bash and remove this part of the first line:
"$TERM" != screen
So this
if [[ "$TERM" != screen && "$ITERM_SHELL_INTEGRATION_INSTALLED" = "" && "$-" == *i* ]]; then
becomes:
if [[ "$ITERM_SHELL_INTEGRATION_INSTALLED" = "" && "$-" == *i* ]]; then
You can use triggers to replicate almost all of the features of shell integration. See the Triggers section near the bottom of this document: https://www.iterm2.com/documentation-shell-integration.html

tmux active on shell startup gives nested tmux session for root

I am using zsh together with tmux. I added to my user's .zshrc the following lines to auto start tmux every time i open a terminal.
[[ $- != *i* ]] && return
[[ -z "$TMUX" ]] && exec tmux
To get the same theme and settings for my root account i created a symlink between root its .zshrc and my own.
Now every time i login as root a new tmux session starts within the current one and a new shell window. Running pstree give this output:
tmux--zsh--sudo--su--tmux
|-zsh-pstree
I wonder why the last tmux process does not spawn a new shell? I expected it to be like
tmux--zsh--sudo--su--tmux--zsh
|-zsh-pstree
With the bash and its default settings logging in as root does not give me a new shell window. How do i need to change the setup to get this behaviour and how do i not start a new tmux session when changing to root?

How to launch tmux –automatically– when konsole/yakuake start?

I discovered tmux possibility recently and I'm using it inside yakuake/konsole (quake-like terminal). However, I have to launch tmux manually every time I start my laptop or restart yakuake.
How to launch tmux –automatically– when yakuake/konsole start ?
A friend advice to use <terminal_emulator> -e tmux.
Konsole
It works with konsole.
I modified the property in the menu to:
konsole -e tmux
Yakuake
However it doesn't work with yakuake.
Based on the Start tmux on every shell login article from the Archlinux wiki, you can start tmux on your shell with the following code at the
Zsh or Bash
Add in your zsh or bash configuration (usually ~/.zshrc or ~/.bashrc) the following code and restart your session:
function start_tmux() {
if type tmux &> /dev/null; then
#if not inside a tmux session, and if no session is started, start a new session
if [[ $HOST == "laptop" && -z "$TMUX" && -z $TERMINAL_CONTEXT ]]; then
(tmux -2 attach || tmux -2 new-session)
fi
fi
}
start_tmux
Fish
Add in your fish configuration (usually ~/.config/fish/config.fish) the following code and restart your session:
function start_tmux
if type tmux > /dev/null
#if not inside a tmux session, and if no session is started, start a new session
if test -z "$TMUX" ; and test -z $TERMINAL_CONTEXT
tmux -2 attach; or tmux -2 new-session
end
end
end
start_tmux
I solved this by creating a Konsole/Yakuake profile (they're one and the same) + made it the default, in which I set up the Command to:
/usr/bin/sh -ilc "tmux attach || tmux new"
Manage profiles + where the profile is located, in case Yakuake/Konsole doesn't start up anymore:
When yakuake is running:
qdbus org.kde.yakuake /yakuake/sessions runCommandInTerminal 0 "tmux"
I haven't tried with Yakuake but I have a one liner shell scripting approach to make it work with Konsole Terminal Emulator.
Konsole emulator set KONSOLE_<something> environment variable on start.
Knowing this fact, we can add this to .zshrc file
[ -z "$KONSOLE_VERSION" ] || tmux
And this will start all KONSOLE windows attached to active tmux session or create one if its the first window.

pager (less) -- get current scroll position?

I am scripting the display of the output of a script (well, it is just the program git diff) with tmux: Once a filesystem change is detected the shell script executes tmux send-keys q enter C-l "git diff" enter which has it effectively refresh the git diff view.
You might consider this similar to functionality provided by iTerm's coprocesses.
Problem is, I want it on refresh to scroll back to the same position that it was in.
One of the reasons for using tmux is that the window is actually a totally normal and interactive terminal session that can be interacted with as normal to scroll around to look at the full output.
But I want to obtain the scroll position somehow.
Suppose I want to actually do computation on the text content of the terminal window itself, exactly like iTerm2's coprocess does, but so that I can use it on Linux (over ssh). Does tmux provide this ability?
I'm unsure about capturing this with a script, but less -N will show line numbers.
And -jn or --jump-target=n can jump to a location.
About iTerm's coprocesses,
tmux has a command pipe-pane that can be used to pipe the input and output of a shell command to the output and input of a target pane specified by -t.
So if I have a shell program, ~/script.sh for example:
#!/usr/bin/env bash
while read line; do
if [[ "$line" = "are you there?"* ]]; then
echo "echo yes"
fi
done
Note that read line will read every line printed to the pane, i.e. the prompt as well.
I can connect its stdin and stdout to pane 0 in my-session:my-window like so:
tmux pipe-pane -IO -t my-session:my-window.0 "~/script.sh"
and then at the prompt, type echo are you there?, and it responds:
$ echo are you there?
are you there?
$ echo yes
yes
Be careful using -IO together as it can easily cause a feedback loop (I had to kill the tmux server a few times while experimenting with this feature, lol).

Resources