How do I clear the scrollback buffer in tmux? - terminal

I want to clear all scrollback history in a particular tmux pane.

This same question has been plaguing me for quite some time. Here's the best I've come up with. Put this into your .tmux.conf file:
bind -n C-k clear-history
This binds ctrl-k to the tmux clear-history command. The -n after bind makes it so you don't have to issue the tmux command prefix (ctrl-b by default). I use bash, so ctrl-l already does the equivalent of typing "clear" at the command line. With these two keys I get a nice ctrl-l, ctrl-k combo, which moves all the scroll buffer off the screen (the "clear") and then deletes all that history (the tmux "clear-history" command).
It's not quite as nice as Terminal's, iTerm's, or Konsole's 1-key combos for clearing it out, but it's a world better than typing in clear-history all the time.

Every answer on here talks about adding new key bindings.
If you just want to do it occasionally you don't need a mapping at all...
Prefix defaults to <Ctrl-b>
Just type <prefix> + : in the relevant pane and then type clear-history and press enter.
If you are on the command line, you can run tmux clear-history in the pane in question for the same effect.
One of the cool things about tmux is that you can just run any of the commands like that... or run them in a shell/script them like tmux command ... or make a keyboard shortcut for them.

As #juanpaco correctly stated, clear-history is the command to clear the scrollback buffer.
I'll add that I like to also clear what's on the screen in the same command.
Issuing a send-keys -R resets (clears) the screen, so I use the following in my .tmux.conf
bind-key b send-keys -R \; clear-history
This clears the screen AND the scrollback buffer.

If you want to combine CTRL-L plus clear-history, add this to your ~/.tmux.conf:
bind u send-keys C-l \; run-shell "sleep .3s" \; clear-history
This even works if you're in a MySQL shell for instance.

I found using send-keys -R to be a little slow - here is another way to clear screen and history with a single command
bind-key C send-keys "clear && tmux clear-history" \; send-keys "Enter"
A nested tmux call is used as the more obvious
bind-key C send-keys "clear" \; send-keys "Enter" \; clear-history
fails to clear the screen's current text from the history - the clear-history command appears to run in a separate thread to send-keys.

Found this works best in TMUX 2.6, clearing the screen, scrollback, but keeping the prompt displayed after.
Uses Ctrl-L
bind-key -n C-l send-keys C-l \; send-keys -R \; clear-history

Way simpler than most, I just created a shell script called cls, and run it whenever I want to clear my screen and scrollback buffer.
All it is is this:
cls
clear;
tmux clear-history;

Ctrl-L is used in console applications to redraw the screen. I found that when bound to send-keys -R it would cause the arrow keys to no longer function correctly in some applications (eg vim, mc).
To retain the redraw functionality in console applications, I used:
bind-key -n C-l if-shell -F '#{alternate_on}' 'send-keys C-l' 'send-keys -R C-l; clear-history'
This requires the tmux option alternate-screen to be on (which it is by default).

if you clear your screen with clear, you can check whether TMUX is set, and create an alias accordingly.
put this in your .bashrc:
if [[ $TMUX ]]; then
alias clear='clear && tmux clear-history'
fi

I've used some of the above plus other sources to come up with:
bind k send-keys C-u \; send-keys C-k \; send-keys " clear && tmux clear-history" \; send-keys "Enter" \; run-shell "sleep .3s" \; send-keys "Up" \; send-keys C-u
The leading space in " clear && tmux clear-history" prevents the command from being written to the history file (providing you have your shell setup to treat leading spaces this way; google "hist ignore space" + the name of your shell for more info). I like to have this command not show up in my history since this is more inline with ctrl-k in the Terminal.
The first send-keys C-u and send-keys C-k will clear whatever is currently typed at the prompt to ensure that the " clear && tmux clear-history" is successful (e.g., if you've typed "ABCDEFG" at the prompt and have your cursor between the D and the E, this ensures that "ABCD clear && tmux clear-historyEFG" is not sent to the shell, which would fail).
The send-keys "Up" and last send-keys C-u clears out the last items from your shells internal history. Even with the trailing space mentioned above the internal history of the shell will include the " clear ..." line. Sending up and Ctrl-u gets rid of this.
Lastly, in iTerm I set ctrl-k to map to ctrl-a k (I have my tmux prefix set to ctrl-a), so I can type ctrl-k which is what my hands want to do from so many years of doing so. I do this, by going to iTerm > Preferences > Profiles > Keys and adding a shortcut to send the hex code "0x01 0x6B". There's a great article here which gives more info on using hex codes with tmux and iTerm: http://tangledhelix.com/blog/2012/04/28/iterm2-keymaps-for-tmux/
That pretty much gives me ctrl-k with tmux. The only thing that still kinda nags at me is that the real ctrl-k without tmux doesn't have problems if you currently have something typed at the prompt and will preserve what you've typed while clearing the screen. As mentioned, this approach needs to clear what's typed so the " clear ..." command doesn't fail. But it's pretty damn close!

For a quick fix to clear individual tmux panes you could set up an alias...
# Tmux Clear pane
alias tc='clear; tmux clear-history; clear'

So, I've been using plu's approach from above for a while, but I got fed-up with the limitations thereof (basically, the ⌃L passed through is meaningless unless piped to a program that understands it.)
So I've improved upon the various approaches in different answers to this thread; although complex, this approach works with both shells and other commands:
# ⌃K: Clears the current pane (from <https://stackoverflow.com/a/34162098>)
bind-key -n C-k \
if-shell "test \"$(printf '#{pane_current_command}' | tail -c 2)\" = sh" \
"send-keys C-l ; run-shell 'sleep .3s' ; clear-history" \
"split-window -vp 100 ; clear-history -t ! ; kill-pane"
Try it with tail -f /private/var/log/system.log or something!
Caveats:
There's one important note here: this is invisibly resizing the pane being cleared, if it's not a shell. This can trigger resizing behaviour in some command-line applications listening for SIGWINCHes; but my reasoning is that this isn't a big problem, because those are programs you're very likely not going to be trying to ‘clear’ anyway.
In addition, the shell-quoting situation is already a mess, and can easily become more of one when embedding #{pane_current_command}, so be careful, you may have to modify this based on your default-command setting.
The same applies to my testing of the end of that command matching "sh"; if you have a default-command of something like /bin/bash --login or something complicated involving exec, the actual command may not end with "sh"; use ⌃B : to execute display-message '#{pane_current_command}' if you want to see what is being tested against.

After a lot of research and spending time. I have found the best way for me on zsh and terminal.app
I am using prefix-c to clear the screen and prefix-C to clear the history and the scroll buffer and leaving no lines above because I find it annoying.
Without Vim
# clear screen
bind c send-keys 'C-l'
# clear screen and history
bind C send-keys -R \; send-keys C-l \; clear-history \; send-keys
With Vim
# check if the pane is running vim
is_vim="ps -o state= -o comm= -t '#{pane_tty}' \ | grep -iqE '^[^TXZ ]+ +(\\S+\\/)?g?(view|n?vim?x?)(diff)?$'"
# clear screen
bind c if-shell "$is_vim" "send-keys c" "send-keys 'C-l'"
# clear screen and history
bind C send-keys -R \; send-keys C-l \; clear-history \; send-keys

why not? bind -n C-l send-keys C-l

If you want a complete pane clearing, another option is to temporarily resize the pane to one line, clear the history, then resize it back. This should work possibly flicker-free with one tmux chain of commands. The advantage is that it works regardless of what program is running in the pane. Of course this makes the shell script logic a bit more complicated.
bind-key -n F11 run "
if [[ #{window_panes} == "1" ]] ; then
tmux send-keys C-l; sleep 0.1 ; tmux clear-history ;
else
restored_height=$((#{pane_height} + #{pane_at_bottom}));
tmux resize-pane -y 1 \\; clear-history \\; resize-pane -y \${restored_height} ;
fi
"

If you struggling on OSX with Iterm:

Related

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 run tmux with shell command

I want to run tmux with shell command in it
I try:
tmux new-session -d -s foo 'echo intmux'
( I want to use this later in bash script)
But it doesn't works. I expect that:
1) Tmux open new window ( like tmux new )
2) command echo intmux will be called
1) Tmux open new window ( like tmux new )
You will not see a new session, because you create it using -d (detached) flag.
What you want (execute a command and leave a shell open) can be easily achieved with:
tmux new -s foo 'echo intmux; $SHELL'
Another tricky option bound to specific (bash) shell:
tmux new-session -s foo 'bash --rcfile <(echo ". ~/.bashrc; echo intmux")'
This allows to preserve default behavior (reading . ~/.bashrc) and pass your arbitrary command.
You can run
tmux new-session '-s foo' \; neww '-t 2 -n echo' mc
But that spawns another window in the new session running your command so possibly you want to close the first window
tmux new-session '-s foo' \; neww '-n echo' mc \; kill-window '-t 1'

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.

Fullscreen TMUX sessions selection

I've found TMUX's choose-tree command to be quite useful when navigating between sessions, but I dislike it only displaying inside of the current pane. I'd prefer it to overtake my entire screen.
Inside my tmux.conf I'm attempting to write something to do just that, but haven't quite figured it out:
# ~/.tmux.conf
bind-key a resize-pane -Z \; choose-tree
My trigger command Ctrl-a + a will zoom the current tmux pane to be fullscreen and run choose-tree inside of it. Unfortunately this leaves the pane zoomed in.
Any ideas how I can unzoom the pane afterwards, or a different approach for fullscreen TMUX session selection?
With Tmux v2.7 zooming the pane for session-selection gets fairly simple, just add the -Z option
# ~/.tmux.conf
bind-key a choose-tree -Z
It's not very clear from the documentation, but you can use the -c parameter to execute a command when you choose the window.
In this way you can toggle back the pane and then switch to the selected window:
# ~/.tmux.conf
bind-key a resize-pane -Z \; choose-tree -u -c "resize-pane -Z \; select-window -t '%%'"
tmux v2.6 include a new implementation of the choose-tree command that does not support anymore -u and -c commands.
The new syntax for this version to achieve the same is:
# ~/.tmux.conf
bind-key a resize-pane -Z \; choose-tree "resize-pane -Z \; select-window -t '%%'"

How to create panes that's won't be destroyed when I quit the command that it's running inside?

I would like to create panes in tmux like so :
$ tmux new-session -d -s mysession "while true; do sleep 1; ls; done"
$ tmux split-window -h "while true; do sleep 1; ls -l; done"
Running it this way, when I cancel the command that is running in the pane (window) I close it immediately. How to avoid this behaviour ?
Use the remain-on-exit window option to mark the window (and any panes it contains) to remain after the command it runs exits.
tmux new-session -d -s mysession "while true; do sleep 1; ls; done"
tmux set-option -t mysession:0 remain-on-exit
When you kill the command, the window will remain, and [the pane] will be labeled "Pane is dead". To restart the same command, issue respawn-window. To start a new command in the window (say, an interactive bash session), issue respawn-window bash.
respawn-window (and respawn-pane, which I forgot about but can be use to target an individual pane within a window) also take a -k option, which can be used to kill whatever is running in a window and either restart the command or start a new command. You could add something to your .tmux.conf like
bind-key C-c respawn-pane -k bash
Then, in any active pane, you can type Control-C to kill whatever is running in the pane and replace it with an interactive shell (remain-on-exit would not be necessary in this case, as you are immediately replacing the old command with a new one).

Resources