How to close all windows to the right in tmux - tmux

Is there a way to issue a command to close all tmux windows unless something is open in that window? For example, an open file, a running process, etc.?
I am hoping for something that functions as a web browser where you can right click and select close all other tabs to the right. I'd like to issue this in tmux, and similar to the web browser example, have "busy" windows or panes prompt me to close them or silently fail to close.
I have seen this question, but I don't necessarily want to issue the command to all windows.

Here's a shell alternative:
for win_id in $(tmux list-windows -F '#{window_active} #{window_id}' | awk '/^1/ { active=1; next } active { print $2 }'); do tmux kill-window -t "$win_id"; done
And here's the same (readable version):
for win_id in $(tmux list-windows -F '#{window_active} #{window_id}' | \
awk '/^1/ { active=1; next } active { print $2 }')
do
tmux kill-window -t "$win_id"
done
Edit: I made a plugin with this!
https://github.com/pschmitt/tmux-forsaken

I just built a script to do so, here it is:
#!/usr/bin/env python3
import subprocess
import os
import re
result = subprocess.run(['tmux', 'list-windows'], stdout=subprocess.PIPE)
result = result.stdout.decode('utf-8')
lines = result.splitlines()
should_close_next = False
for line in lines:
if should_close_next:
window = line.split(':')[0]
os.system(f'tmux kill-window -t {window}')
continue
match = re.search("active", line)
if match:
should_close_next = True
And to integrate it with your tmux add to your tmux.conf
bind-key "k" run-shell "kill_panes_to_right.py\n"
Best

Related

TMUX pane tabs, or 'locking/freezing' pane splits in place

When using tmux, I generally have an editor open in a split on top, and a shell at the bottom. Right now, I'm writing a python script, and on the bottom half of the split I can't find a way to toggle back and forth between ipython and bash: the best I can do is create a nested split between those two, sharing the bottom half of the screen. Right now this looks something like the following.
Is there something like tabs within a pane, so I can switch back and forth between bash/ipython while keeping the editor locked/frozen in place at the top? It's not ideal right now to have to choose between switching to a new tab for one of the shell prompts or using these tiny splits. Tmux is so flexible it seems like there'd be a way to do this straightforward pane-lock. Thanks
Resolved using nested tmux sessions. I based my solution on a much-stripped down version of nested-tmux. I launch a nested session and then use tabs within that nested session. To launch a nested session, I use the following script tmux-nested.sh (adapted from the nested-tmux repo):
#!/bin/sh
TMUX_PARENT=$(basename "$TMUX")
TMUX_PARENT="${TMUX_PARENT%%,*}"
export TMUX_PARENT
_SOCK="r$RANDOM"
tmux -L "$_SOCK" new-session -s "$_SOCK"
This creates a nested session with socket given a random filename (a hardcoded value wouldn't permit multiple nested sessions, say in different tabs in the parent session).
In my .tmux.conf file, I add the following line on startup to change the tmux prefix for nested sessions:
# nested session logic
if-shell '! [ -z "$TMUX_PARENT" ]' 'set-option -g prefix C-b'
(where my normal prefix is a backtick)
EDIT:
I expanded this function into a much more robust implementation, which can be found below:
# Nest tmux sessions
tmux_nested() {
local usagestring='usage: tmux-nested [-n | -a nested-session-# | -l]'
if [[ -z $TMUX ]]; then
# ensure invoked within active session
echo "'tmux_nested' should be invoked inside an active tmux session"
return 1
fi
# read flags and check for number of existing nested sessions
local nested session_name
nested=$(tmux list-sessions -F '#{session_name}' | \
ggrep -P '^nested[\d]+' --color=never | sort -V)
while getopts ':lna:' opt; do
case $opt in
l)
[[ -z $nested ]] && nested="No nested sessions running"
echo "$nested" && return 0;;
n)
# if new session requested: create, set <C-b> tmux prefix, and attach
for (( i = 1;; i++ )); do
# get lowest available numeric value for new session name
if ! tmux has-session -t "nested$i" 2> /dev/null; then
session_name="nested$i" && break
fi
done
tmux new-session -ds "$session_name"
tmux send-keys -t "$session_name" \
"tmux set prefix C-b" ENTER "clear" ENTER
env TMUX='' tmux attach -t "$session_name"
return $?;;
a)
# attach to specified session if requested
session_name="nested${OPTARG}"
if ! env TMUX='' tmux attach -t "$session_name"; then
echo "Try 'tmux_nested -l'?" && return 1
fi;;
*) echo "$usagestring" && return 1;;
esac
done
# incorrect invocation, report incorrect invocation and exit
echo "$usagestring" && return 1
}

tmux: list all the tmux windows with last 5 lines of output

I am running a lot of tmux session like
Each tmux session is started as:
today=`date +%Y-%m-%d-%H_%M_%S_%N`
tmux new-session -d -s "$today" zsh /home/path/to/script.sh "with_params"
If i want to only view the list of tmux sessions. I can do by
tmux ls | awk '{print $1}';
Now what i want is to monitor their output using the while loop to show the session name and the recent output:
while true;
do;
echo "##########################################"
??? For list of tmux session; do
sleep 1;
??? session name
??? recent last 5 lines of output
done
echo "##########################################"
done;
??? : What commands should i use
You can use capture-pane to show the last five lines of output:
tmux capture-pane -p -S- -E-|sed '/^$/d'|tail -5
Add -t to specify the pane you want to see - if you just give a session it will use the active pane in the current window.
Add -e if you want colour sequences included.

zscroll text in the tmux status bar

I am trying to configure my .tmux.conf to display a scrolling string of text. For what it is worth, the scrolling text is an aviation weather observation that is scraped using a really ugly bash script that is defined in .zshrc as follows:
function scrollMetar {
curl -s "https://www.aviationweather.gov/metar/data?ids=kjyo&format=raw&date=&hours=0" | awk '/Data\ starts\ here/{getline; print}' | html2text | zscroll -l 14 -n 0
}
I want to take the scrolling output from the scrollMetar command and have that scroll on the tmux status line.
My current .tmux.conf section looks like this:
set-option -g status-left "\
#[fg=colour7, bg=colour241]#{?client_prefix,#[bg=colour167],} ❐ #S \
#[fg=colour241, bg=colour237] \
#(echo 'TEST TEXT') \
#{?window_zoomed_flag, 🔍,} "
Where the echo 'TEST TEXT' is should be where the scrollMetar would go, but when inserted doesn't output anything.
I am guessing that this maybe a limitation of tmux, but I would be grateful for any advice and I am completely open to alternate implementations.
Okay, so it seems like .tmux.conf did not like calling the function, or could not find it. Putting the function in a executable shell script fixed the problem.

switch to terminal input after executable gnuplot script

This is a gnuplot scripting question on unix like systems.
For shell executable gnuplot scripts starting like:-
#!/opt/local/bin/gnuplot
how do you switch to the gnuplot prompt in the starting terminal session, at the end of the script?
Adding
load "/dev/stdin"
at the end, switches the input, but gives no user prompt.
I would like to let the user replot their own data over the setup and background generated by the script, and/or enter other gnuplot commands. I am looking for an elegant solution within gnuplot. When using the #!/opt/local/bin/gnuplot -c in a gnuplot scriptfile (after a chmod +x), I would like ./script.gp to work the same way as call "script.gp" from gnuplot does. This is so we could subsequently replot "info.dat" at a gnuplot prompt in each case. I want to switch gnuplot from batch mode to interactive at the end of the script (probably like in the way a startup file would). I can't remember or find the command/trick for this (load "/dev/stdin" is close).
The plot window in this case is AquaTerm, gnuplot 5.0 patchlevel 3 (macports), and the terminal session is OS X "Terminal". --persist seems unhelpful in changing the experience.
You want to send a load of plot commands from a file to gnuplot, then send a load of commands from your user's terminal, which suggests something like this:
{ cat plot.gp; while read cmd; do echo "$cmd"; done; } | gnuplot
Or if I flesh that out a bit:
{ cat plot.gp; while :; do >&2 echo -n "gnuplot> "; read -re c; [ "$c" == "quit" ] && break; echo "$c"; done; } | gnuplot
I am using this plot.gp
set xrange [-5:5]
plot sin(x),cos(x),x*x
That basic functionality can be spruced up quite a lot, if you feel fancy:
#!/bin/bash
gpfile=$1
{
# Show user gnuplot version - on stderr because stdout is going to gnuplot
gnuplot -e "show version" >&2
# Strip shebang (but not comments) from plot commands and send to gnuplot
grep -v "^#!" "$gpfile"
# Show plot commands from file to user - on stderr and prefixed with pseudo-prompt
grep -v "^#!" "$gpfile" | sed 's/^/gnuplot> /' >&2
# Read user input and forward onto gnuplot
while :; do
>&2 echo -n "gnuplot> "
read -re c
[ "$c" == "quit" ] && break
echo "$c"
done
} | gnuplot
You would save the above in a file called plotandinteract in your HOME directory, then make it executable (just once) with:
chmod +x $HOME/plotandinteract
Then you can run it with:
$HOME/plotandinteract SomePlotFile
There's probably a much more elegant solution with Tcl/expect but I can't work that out - looks like I need #GlennJackman again :-)

tmux maximize/minimize pane bug -- "Session not found: tmp"

description of what's happening:
when minimizing a maximized pane, this message appears at bottom of terminal window: "Session not found: tmp"
pane appears to return to same place as initial/previous session
but the new tmp window (that was opened when the pane was first maximized) fails to close and appears in the list of windows (in the status bar at the bottom of tmux)
my hunch is kill-window -t tmp (in the below .tmux.conf code) is where things break. since executing a command in the tmp window appears to rename the window, kill-window -t tmp won't work.
so my question is: how could i alter .tmux.conf to prevent this from happening?
steps to recreate bug:
(note: you would need to have modified .tmux.conf for these commands to work)
start tmux and create session w/ at least two panes
maximize one pane using [prefix] + [up]
execute a shell command in maximized pane (*)
minimize pane using [prefix] + [down]
(*) if pane is maximized and minimized w/out executing a command in the shell this problem does not appear to occur. i.e. if you're editing a file in a pane, then maximize that pane, and only edit/save the file (w/out exiting and then executing another command), then minimize -- the bug doesn't occur.
30s youtube clip showing what happens: http://youtu.be/WMdOeJdOYuU
code that might be causing the error (from ~/.tmux.conf):
unbind Up
bind Up new-window -d -n tmp \; swap-pane -s tmp.0 \; select-window -t tmp
unbind Down
bind Down last-window \; swap-pane -s tmp.0 \; kill-window -t tmp
[edit: HERE IS THE SOLUTION]
thanks to a helpful #tmux irc'er (who has this link and whom i will happily give credit) this question is solved. i don't yet have enough cred to answer this question so i'm posting the solution here.
the solution is to add set-window-option -g allow-rename off to ~/.tmux.conf
this works b/c tmp doesn't get renamed so kill-window -t tmp can properly execute.
(thx for the help and feel free to answer this so i can give you credit!)
You want allow-rename set to off, at least for that one window:
set-window-option -g allow-rename off

Resources