How to completely close terminal (Ubuntu bash) from TMUX session? - bash

Can someone please help as how can I close the bash terminal completely from inside of TMUX session (closing TMUX session as well)?
Below code is from my .bashrc where TMUX session starts as soon as terminal launches
if command -v tmux &> /dev/null && [ -z "$TMUX" ]; then tmux attach -t default -c "$HOME" || tmux new -s default -c "$HOME" fi
Thanks!

You can use tmux detach -P to both detach and send HUP to the parent process, which should make it exit as well.

Related

Bash script is not reverting the name on timeout

I have a small Bash script to rename tmux window for heroku cli and rename it back when I close the heroku session.
heroku(){
windowname=$(tmux display-message -p '#W')
tmux rename-window "heroku $(echo "$#")"
command heroku "$#"
tmux rename-window "$windowname"
}
But heroku has a timeout feature, if it stays too long it will close the connection.
In this case, my script will not revert the name of tmux window.
How to catch that timeout and revert the name of tmux window?
Thanks to tripleee and ceving I rewrote my script to this:
heroku(){
windowname=$(tmux display-message -p '#W')
trap "{ tmux rename-window "$windowname" }" EXIT
tmux rename-window "heroku $*"
command heroku "$#"
tmux rename-window "$windowname"
}

Run command in new background tmux window and wait for process to finish

I'm trying to use tmux in a script, so that it runs a command that takes some time (let's say 'ping -c 5 8.8.8.8', for example) in a new hidden pane, while blocking the current script itself until the ping ends.
By "hidden pane", I mean running the command in a new pane that would be sent in background, and is still accessible by switching panes in order to monitor and/or interact with it (not necessarily ping).
(cf. EDIT)
Here is some pseudo bash code to show more clearly what I'm trying to do:
echo "Waiting for ping to finish..."
echo "Ctrl-b + p to switch pane and see running process"
tmux new-window -d 'ping -c 5 8.8.8.8' # run command in new "background" window
tmux wait-for # display "Done!" only when ping command has finished
echo "Done!"
I know the tmux commands here don't really have any sense like this, but this is just to illustrate.
I've looked at different solutions in order to either send a command in background, or wait until a process has finished in an other pane, but I still haven't found a way to do both correctly.
EDIT
Thanks to Nicholas Marriott for pointing out the -d option exists when creating a new window to avoid switching to it automatically. Now the only issue is to block the main script until the command ends.
I tried the following, hoping it would work, but it doesn't either (the script doesn't resume).
tmux new-window -d 'ping -c 5 8.8.8.8; tmux wait -S ping' &
tmux wait $!
Maybe there is a way by playing with processes (using fg,bg...), but I still haven't figured it out.
Similar questions:
[1] Make tmux block until programs complete
[2] Bash - executing blocking scripts in tmux
[3] How do you hide a tmux pane
[4] how to wait for first command to finish?
You can use wait-for but you need to give it a channel and signal that channel when your process is done, something like:
tmux neww -d 'ping blah; tmux wait -S ping'
tmux wait ping
echo done
If you think you might run the script several times in parallel, I suggest making a channel name using mktemp or similar (and removing the file when wait-for returns).
wait-for can't automatically wait for stuff like pane or windows exiting, silence in a pane, and so on, but I would like to see that implemented at some point.
The other answers are only working if you're already within a tmux session.
But if you are outside of it you've to use something like this:
tmux new-session -d 'vi /etc/passwd' \; split-window -d 'vi /etc/group' \; attach
If you want to call this within a script you should check whether or not "$TMUX" is set. (Or just unset to force a nested tmux window).
#!/bin/sh
export com1="vi /etc/passwd"
export com2="vi /etc/group"
if [ -z $TMUX ]
then
export doNewSession="new-session -d 'exit 0'"
else
export doNewSession=""
fi
tmux $doNewSession \; split-window -d $com1 \; split-window -d $com2 \; attach;
[ -z $TMUX ] && exit 0
My solution was to make a named pipe and then wait for input using read:
#!/bin/sh
rm -f /wait
mkfifo /wait
tmux new-window -d '/bin/sh -c "ping -c 5 8.8.8.8; echo . > /wait"'
read -t 10 WAIT <>/wait
[ -z "$WAIT" ] &&
echo 'The operation failed to complete within 10 seconds.' ||
echo 'Operation completed successfully.'
I like this approach because you can set a timeout and, if you wanted, you could extend this further with other tmux controls to kill the ongoing process if it doesn't end the way you want.

How to detect if tmux is attached to a session in bash?

I have a .sh file which create a new session for tmux and add some windows, the file should be used only when no session exist. For instance:
tmux new-session -A -s `ax` -n ui -d
# add windows and other magic here...
I want prevent creating a session with the same name and recreating the windows in case the .sh file is accidentally re executed and the session is running.
Basically what I need is:
If a tmux session ax does not exist with that session name, create that session. If
I am not attached to a tmux session, attach to that session.
I would like to know how to detect if a tmux session exist and if tmux is attached to it, in this example ax is running and preventing the execution of the .sh script or if the session does not exit I want to re-execute the .sh script.
Currently I was thinking to use:
tmux ls | grep attached
I would like to know if you know a better way.
It's a little hard to understand what you mean. I'm interpreting it as
if a tmux session does not exist with that session name, create it. If I am not attached to a tmux session, attach to that session name.
If this is wrong, please comment.
I have similar functionality in my scripts. All I do is
tmuxstart() {
tmux ls | grep "sess" && { tmux a -t sess; return 0; }
#rest of tmux script to create session named "sess"
tmux a -t sess
}
If the session named "sess" exists, then I execute the next 2 grouped commands on the line (attach to it and exit the function).
Note that I do not have to check if I'm already attached to the function. tmux does this automatically. If you try to attach to a tmux session while in a session, it will respond
sessions should be nested with care, unset $TMUX to force
and not recursively attach. Tmux is smart enough to keep us from shooting ourselves in the foot.
You can use $TMUX to detect if already attached, my code is:
if [ ! "$TMUX" ]; then
tmux attach -t main || tmux new -s main
fi
I use this in my ~/.bashrc so if no sessions exist, start them & detach from all but ipfs session.
IPFS_SESSION=$(tmux attach-session -t ipfs 2>&1)
if [ "$IPFS_SESSION" == "sessions should be nested *" ]; then
unset TMUX
else
if ! tmux has-session -t sql; then tmux new-session -d -s sql; fi
if ! tmux has-session -t tmp; then tmux new-session -d -s tmp; fi
if ! tmux has-session -t ytdl; then tmux new-session -d -s ytdl; fi
if ! tmux has-session -t ipfs; then tmux new-session -s ipfs; fi
fi

How can I find which program is running on a specific tmux session?

On a remote machine, I have a tmux session with ID selu, and I am running a python program
python test.py that runs a C++ program main.cpp with different parameters several times. I want to learn the parameters of C++ program running at the moment in that session. How can I do this?
You can rely on the run-shell command. Here is an example of how to grep the current active process of the active pane.
bind-key M-v run-shell 'T=$(tmux display -p "#{pane_tty}" | sed "s=/dev/=="); if pgrep -t$T "fzf|vim|elvish" &> /dev/null; then tmux send-key M-v; elif pgrep -t$T "gdb" &> /dev/null; then tmux send-key PageUp; else tmux copy-mode; fi'
You can also add -t <your session> to run-shell in order to specify the needed session.

How can I make TMUX be active whenever I start a new shell session?

Instead of having to type tmux every time, how could I have tmux always be used for new session windows?
So if I have no terminal windows open and then I open one, how can that first session be in tmux?
Seems like a .bashrc sort of thing perhaps?
warning this can now 'corrupt' (make it unable to open a terminal window - which is not good!) your Ubuntu logins. Use with extreme caution and make sure you have a second admin account on the computer that you can log into in case you have the same problems I did. See my other answer for more details and a different approach.
Given that warning, the simplest solution can be to append the tmux invocation to the end of your .bashrc, e.g.
alias g="grep"
alias ls="ls --color=auto"
# ...other stuff...
if [[ ! $TERM =~ screen ]]; then
exec tmux
fi
Note that the exec means that the bash process which starts when you open the terminal is replaced by tmux, so Ctrl-B D (i.e. disconnect from tmux) actually closes the window, instead of returning to the original bash process, which is probably the behaviour you want?
Also, the if statement is required (it detects if the current bash window is in a tmux process already) otherwise each time you start tmux, the contained bash process will attempt to start its own tmux session, leading to an infinite number of nested tmuxen which can be, err, quite annoying (that said, it looks cool).
However, there is a very small risk this can make bash behave in a way that other programs don't expect, since running bash can possibly cause it to turn into a tmux process, so it might be better to modify how you start your terminal emulator.
I use a small executable shell script ~/bin/terminal (with ~/bin in $PATH, so it is found automatically) that looks a bit like:
#!/bin/sh
exec gnome-terminal -e tmux
(I don't use gnome-terminal, so you might have to remove the exec, I'm not sure.)
Now whenever you run the terminal scipt you have a terminal with tmux. You can add this to your menu/desktop/keyboard shortcuts to replace the default terminal.
(This approach also allows you to more easily customise other things about the terminal emulator later, if you ever desire.)
My original, accepted answer, stopped working on my Ubuntu14 system after a recent upgrade.
Using either
[ -z "$TMUX" ] && command -v tmux > /dev/null && TERM=xterm-256color && exec tmux
or
[ $TERM != "screen" ] && TERM=xterm-256color && exec tmux
would stop me from being able to even login. I was only able to resolve this due to having a second admin login on the computer.
The fix for me on Ubuntu (and in osx too) was to change my terminal program to actually run tmux instead, i.e.
I still have
[ `uname -s` != Linux ] && exec tmux
as my last .bashrc line but that his only for my Mac OSX systems now.
If you want to have a single tmux session, put the following in your ~/.bashrc for bash or ~/.zshrc for zsh:
tmux attach &> /dev/null
if [[ ! $TERM =~ screen ]]; then
exec tmux
fi
The tmux attach line is to make sure if there is a session it attaches to and if there was no session you will not get the warning about "no session".
For me, I would love my tmux to be started every time I shell onto my remote machine, and when I detach or exit from tmux, the connection should be closed automatically. After digging into this issue for a while, the following code does exactly what I want and is believed to be the most optimized to the best of my knowledge.
[ -z "$TMUX" ] && { tmux attach || exec tmux new-session && exit;}
Note this line should be the first line in you bashrc file to make sure it is loaded first. We can't put an "exec" call in front of "tmux attach" because after the exec replaces the bash process with the tmux one, the connection will be closed even if there are no sessions to attach to. Therefore we need an "exit" call to terminate the connection after we detach or exit from the attached sessions. But putting an "exec" in front the new-session command is fine as that's the last command to be executed.
Append following line of code to the end of .bashrc,
[[ $TERM != "screen" ]] && exec tmux
I just made it a keyboard shortcut (in Linux Mint not Ubuntu; so I'm not sure if it is this easy)...
It might be hard to see, but the custom shortcut is gnome-terminal --window --maximize -e tmux. This starts a new gnome-terminal window maximized and then executes tmux for you.
I additionally have another custom shortcut that starts a "normal" gnome-terminal maximized (it's the same without the -e tmux).
I feel this is the best way because you can start whatever terminal whatever way you want and is the most customizable way.
I started with this https://wiki.archlinux.org/index.php/Tmux#Bash and enhanced it to reclaim detached sessions and make new ones if all sessions were already attached
# .bashrc
case $- in
*i*)
if command -v tmux>/dev/null; then
if [[ ! $TERM =~ screen ]] && [[ -z $TMUX ]]; then
if tmux ls 2> /dev/null | grep -q -v attached; then
exec tmux attach -t $(tmux ls 2> /dev/null | grep -v attached | head -1 | cut -d : -f 1)
else
exec tmux
fi
fi
fi
;;
esac
To enable tmux for login and ssh sessions, you can add this to the end of your .bashrc:
# enable tmux at login
PNAME="$(ps -o comm= $PPID)";
if [ $PNAME == "login" ] || [ $PNAME == "sshd" ] ; then
exec tmux
fi
This script looks for the parent process of the bash shell. If bash was started from logging in or from ssh, it will execute tmux. If you want this to work with a GUI terminal, you can add that in there as well. For example, if you want to start tmux automatically when you start Ubuntu's standard gnome-terminal, you would use this:
PNAME="$(ps -o comm= $PPID)";
if [ $PNAME == "login" ] || [ $PNAME == "sshd" ] || [ $PNAME == "gnome-terminal" ] ; then
exec tmux
fi
I've tested the above on Live Ubuntu Desktop and I was able to log in afterwards. This should not break the GUI login unless it invokes the login command to log in. I am not aware of a linux GUI that does this.
Within xfce4 (I'm running Fedora 24 XFCE spin, it's great), I've found the simplest solution is to edit panel shortcuts to so they run:
xfce4-terminal -e tmux
This same command can be used to replace the Keyboard Application Shortcut.
I had previously inserted an if statement into my .bashrc, but it caused login to fail (loop back to the login box whenever a correct password was entered).
The command for Thunar's Open Terminal Here command differs slightly. To change that goto:
Thunar > Edit > Configure Custom Actions... > Open Terminal Here > Edit button, and replace:
exo-open --working-directory %f --launch TerminalEmulator
with: xfce4-terminal --working-directory %f -e tmux
A one-liner that also makes sure the terminal type is set correctly for 256 colors:
[ -z "$TMUX" ] && export TERM=xterm-256color && exec tmux
How about adding
# If not running interactively, do not do anything
[[ $- != *i* ]] && return
[[ -z "$TMUX" ]] && exec tmux
to your .bashrc. It also works for zsh.
Taken from https://wiki.archlinux.org/index.php/Tmux#Start_tmux_with_default_session_layout

Resources