Occasionally, I’ll be running a command in tmux that prints a lot of output - then realize midway that I’d like to save it for further inspection (eg., bootloader recompilation errors on system upgrade).
After digging around for a while, I found an excellent starting point on StackOverflow and modified it:
1 | bind-key -T copy-mode-vi S command-prompt \ |
To use this:
- jump into copy mode (Vi) with
<TMUX PREFIX> [
- scroll up however far as needed
- leave the cursor at the line where the scrollback should start
- type
SHIFT s
, and either use the default timestamped filename or overwrite it with a custom one - hit
<ENTER>
to save to the file
The command automatically calculates the scrollback position and the cursor offset to pick the starting line, and writes everything from that point on downwards to the target file.
command breakdown
Bind S
(capital s) in Vi copy mode & prompt for a filename:
1 | bind-key -T copy-mode-vi S command-prompt -p 'Save scrollback (start at cursor):' |
Autogenerate a default filename with an instant timestamp. The client_activity
event was picked because it continues to update as the user interacts with tmux, rather than something like buffer_created
which would not update when taking multiple scrollback saves. Use tmux string formatting (can be found under FORMATS
section in the manpage, or on the official Wiki) to generate a YearMonthDayHourMinuteSecond
timestamp.
1 | -I './tmuxscrollback-history-#{t|f|%%Y%%m%%d%%H%%M%%S:client_activity}.txt' |
The command that the command-prompt
directive will execute. The -F
flag is required for the calculation of the scrollback offset defined in the next section, and the -S
flag sets the starting line number.
1 | -F 'capture-pane -S |
Calculate the offset. First, the entire calculation is multplied by -1
to provide a negative offset into the scroll buffer. #{e
marks this as an execution block, and the *
(after the |
delineator) marks the mathematical operation that will happen between the next 2 values, which are specified after the :
(-1
and the offset).
1 | #{e|*:-1, ... } |
The offset is calculated by subtracting the scrollback position into the pane history from the cursor offset in the currently visible pane. These two variables are defined as:
#{scroll_position}
the scrollback position during copy mode. This is anchored against the top of the tmux pane, and is zero-indexed when copy mode is initialized at the very bottom of the scrollback history.#{copy_cursor_y}
the cursor offset, which is zero-indexed against the top of the currently visible tmux pane.
The scroll_position
is the larger value unless the user does not scroll up. This makes the multiplication by -1
a much better choice than prepending the equation with a minus sign: the cursor offset copy_cursor_y
reduces the starting line position except when the pane has not been scrolled up, which instead results in a positive value.
1 | ... #{e|-:#{scroll_position},#{copy_cursor_y}} ... |
Save the buffer that was just calculated into the filename, using the variable %1
. Then, clear it so it doesn’t linger in the user’s copy buffer.
1 | ; save-buffer %1 ; delete-buffer' |
references
- tmux official Wiki
https://github.com/tmux/tmux/wiki - tmux Wiki FORMATS
https://github.com/tmux/tmux/wiki/Formats