1*eda6f593SDavid van Moolenbroek#!/bin/bash
2*eda6f593SDavid van Moolenbroek#
3*eda6f593SDavid van Moolenbroek# By Victor Orlikowski. Public domain.
4*eda6f593SDavid van Moolenbroek#
5*eda6f593SDavid van Moolenbroek# This script maintains snapshots of each pane's
6*eda6f593SDavid van Moolenbroek# history buffer, for each tmux session you are running.
7*eda6f593SDavid van Moolenbroek#
8*eda6f593SDavid van Moolenbroek# It is intended to be run by cron, on whatever interval works
9*eda6f593SDavid van Moolenbroek# for you.
10*eda6f593SDavid van Moolenbroek
11*eda6f593SDavid van Moolenbroek# Maximum number of snapshots to keep.
12*eda6f593SDavid van Moolenbroekmax_backups=12
13*eda6f593SDavid van Moolenbroek# Names of sessions you may wish to exclude from snapshotting,
14*eda6f593SDavid van Moolenbroek# space separated.
15*eda6f593SDavid van Moolenbroekignore_sessions=""
16*eda6f593SDavid van Moolenbroek# The directory into which you want your snapshots placed.
17*eda6f593SDavid van Moolenbroek# The default is probably "good enough."
18*eda6f593SDavid van Moolenbroekbackup_dir=~/.tmux_backup/snapshot
19*eda6f593SDavid van Moolenbroek
20*eda6f593SDavid van Moolenbroek########################################################################
21*eda6f593SDavid van Moolenbroek
22*eda6f593SDavid van Moolenbroek# Rotate previous backups.
23*eda6f593SDavid van Moolenbroeki=${max_backups}
24*eda6f593SDavid van Moolenbroekwhile [[ ${i} != 0 ]] ; do
25*eda6f593SDavid van Moolenbroekif [ -d ${backup_dir}.${i} ] ; then
26*eda6f593SDavid van Moolenbroek  if [[ ${i} = ${max_backups} ]] ; then
27*eda6f593SDavid van Moolenbroek    rm -r ${backup_dir}.${i}
28*eda6f593SDavid van Moolenbroek  else
29*eda6f593SDavid van Moolenbroek    mv ${backup_dir}.${i} ${backup_dir}.$((${i}+1))
30*eda6f593SDavid van Moolenbroek  fi
31*eda6f593SDavid van Moolenbroekfi
32*eda6f593SDavid van Moolenbroeki=$((${i}-1))
33*eda6f593SDavid van Moolenbroekdone
34*eda6f593SDavid van Moolenbroek
35*eda6f593SDavid van Moolenbroekif [ -d ${backup_dir} ] ; then
36*eda6f593SDavid van Moolenbroek  mv ${backup_dir} ${backup_dir}.1
37*eda6f593SDavid van Moolenbroekfi
38*eda6f593SDavid van Moolenbroek
39*eda6f593SDavid van Moolenbroek## Dump hardcopy from all windows in all available tmux sessions.
40*eda6f593SDavid van Moolenbroekunset TMUX
41*eda6f593SDavid van Moolenbroekfor session in $(tmux list-sessions | cut -d' ' -f1 | sed -e 's/:$//') ; do
42*eda6f593SDavid van Moolenbroek  for ignore_session in ${ignore_sessions} ; do
43*eda6f593SDavid van Moolenbroek    if [ ${session} = ${ignore_session} ] ; then
44*eda6f593SDavid van Moolenbroek      continue 2
45*eda6f593SDavid van Moolenbroek    fi
46*eda6f593SDavid van Moolenbroek  done
47*eda6f593SDavid van Moolenbroek
48*eda6f593SDavid van Moolenbroek  # Session name can contain the colon character (":").
49*eda6f593SDavid van Moolenbroek  # This can screw up addressing of windows within tmux, since
50*eda6f593SDavid van Moolenbroek  # target windows are specified as target-session:target-window.
51*eda6f593SDavid van Moolenbroek  #
52*eda6f593SDavid van Moolenbroek  # We use uuidgen to create a "safe" temporary session name,
53*eda6f593SDavid van Moolenbroek  # which we then use to create a "detached" session that "links"
54*eda6f593SDavid van Moolenbroek  # to the "real" session that we want to back up.
55*eda6f593SDavid van Moolenbroek  tmpsession=$(uuidgen)
56*eda6f593SDavid van Moolenbroek  tmux new-session -d -s "$tmpsession" -t "$session"
57*eda6f593SDavid van Moolenbroek  HISTSIZE=$(tmux show-options -g -t "$tmpsession" | grep "history-limit" | awk '{print $2}')
58*eda6f593SDavid van Moolenbroek  for win in $(tmux list-windows -t "$tmpsession" | grep -v "^\s" | cut -d' ' -f1 | sed -e 's/:$//'); do
59*eda6f593SDavid van Moolenbroek    session_dir=$(echo "$session" | sed -e 's/ /_/g' | sed -e 's%/%|%g')
60*eda6f593SDavid van Moolenbroek    win_spec="$tmpsession":"$win"
61*eda6f593SDavid van Moolenbroek
62*eda6f593SDavid van Moolenbroek    if [ ! -d ${backup_dir}/${session_dir}/${win} ] ; then
63*eda6f593SDavid van Moolenbroek      mkdir -p ${backup_dir}/${session_dir}/${win}
64*eda6f593SDavid van Moolenbroek    fi
65*eda6f593SDavid van Moolenbroek
66*eda6f593SDavid van Moolenbroek    for pane in $(tmux list-panes -t "$win_spec" | cut -d' ' -f1 | sed -e 's/:$//'); do
67*eda6f593SDavid van Moolenbroek      pane_path=${backup_dir}/${session_dir}/${win}/${pane}
68*eda6f593SDavid van Moolenbroek      pane_spec="$win_spec"."$pane"
69*eda6f593SDavid van Moolenbroek
70*eda6f593SDavid van Moolenbroek      tmux capture-pane -t "$pane_spec" -S -${HISTSIZE}
71*eda6f593SDavid van Moolenbroek      tmux save-buffer ${pane_path}
72*eda6f593SDavid van Moolenbroek
73*eda6f593SDavid van Moolenbroek      if [ ! -s ${pane_path} ] ; then
74*eda6f593SDavid van Moolenbroek        sleep 1
75*eda6f593SDavid van Moolenbroek        rm ${pane_path}
76*eda6f593SDavid van Moolenbroek      fi
77*eda6f593SDavid van Moolenbroek    done
78*eda6f593SDavid van Moolenbroek  done
79*eda6f593SDavid van Moolenbroek  tmux kill-session -t "$tmpsession"
80*eda6f593SDavid van Moolenbroek
81*eda6f593SDavid van Moolenbroekdone
82