-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtmux-save.sh
executable file
·197 lines (183 loc) · 6.75 KB
/
tmux-save.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
#!/bin/bash
#######################
# Usage
usage() {
echo "USAGE: ${0} -b | -r [backup_number]"
exit 1
}
#######################
# Config Variables
max_backups=12
ignore_session_list="hosts"
backup_dir=~/.tmuxsave/snapshot
export PATH="${PATH}:/usr/local/bin"
#######################
# Use prompt to get state of pane.
mimic_state() {
prompt='^\<.*@.*:'
prompt_line=$(grep $(eval echo ${prompt}) ${backup_dir}/${pane_full} | tail -n 1)
host=$(printf "${prompt_line}" | cut -d@ -f2 | cut -d: -f1)
working_dir=$(printf "${prompt_line}" | cut -d: -f2 | cut -d\> -f1)
if [ "${host}" != "$(hostname)" ] && [ "${host}" != "" ] ;then
tmux send-keys -t ${pane_full} "ssh ${host}
" #carriage return from previous line
echo "SSH'd to ${host} in ${pane_full}. Sleeping 5 sec..."
sleep 5
fi
tmux send-keys -t ${pane_full} "cd ${working_dir}
" #carriage return from previous line
}
#######################
# Code
if [ ! ${1} ] ;then
usage
fi
while [ ${1} ] ;do
case ${1} in
-b)
task=backup
shift 1
;;
-r)
task=restore
if [ ${2} ] ;then
backup_number=${2}
shift 2
else
shift 1
fi
;;
*)
usage
;;
esac
done
if [ "${task}" = 'backup' ] ;then
##Rotate previous backups.
i=${max_backups}
while [[ ${i} != 0 ]] ;do
if [ -d ${backup_dir}.${i} ] ;then
if [[ ${i} = ${max_backups} ]] ;then
rm -r ${backup_dir}.${i}
else
mv ${backup_dir}.${i} ${backup_dir}.$((${i}+1))
fi
fi
i=$((${i}-1))
done
if [ -d ${backup_dir} ] ;then
mv ${backup_dir} ${backup_dir}.1
fi
##Dump copy from all windows in all available tmux sessions.
if [ ! -d ${backup_dir} ] ;then
mkdir -p ${backup_dir}
fi
for session in $(tmux list-sessions | awk -F: '{print $1}') ;do
for ignore_session in ${ignore_session_list} ;do
if [ "${session}" = "${ignore_session}" ] ;then
continue 2
fi
done
session_size=$(tmux list-sessions | awk -F'[' '/^'${session}': / {print $2}' | awk -F']' '{print $1}')
echo "${session_size}" >${backup_dir}/${session}.size
for window in $(tmux list-windows -t ${session} | awk -F: '{print $1}') ;do
for pane in $(tmux list-panes -t ${session}:${window} | awk -F: '{print $1}') ;do
##backup pane layout
if [ ${pane} -gt 0 ] ;then
tmux list-windows -t ${session} | awk -F'\\[layout ' '/^'${window}':/ {print $2}' | awk '{print $1}' | sed 's/
\]$//' >${backup_dir}/${session}:${window}.layout
fi
pane_full=${session}:${window}.${pane}
##figure out the editing mode so we can select text in history
mode_keys=$(tmux show-window-options -g | awk '/^mode-keys/ {print $2}')
if [ "${mode_keys}" = 'emacs' ] ;then
tmux copy-mode -t ${session}:${window}.${pane} \; send-keys -t ${session}:${window}.${pane} 'M-<' 'C-Space' 'M
->' 'C-e' 'M-w' \; save-buffer -b 0 ${backup_dir}/${pane_full} \; delete-buffer -b 0
elif [ "${mode_keys}" = 'vi' ] ;then
tmux copy-mode -t ${session}:${window}.${pane} \; send-keys -t ${session}:${window}.${pane} g Space G '$' Enter \; save-buffer -b 0 ${backup_dir}/${pane_full} \; delete-buffer -b 0
fi
if [ ! -s ${backup_dir}/${pane_full} ] ;then
rm ${backup_dir}/${pane_full}
fi
done
done
done
elif [ "${task}" = 'restore' ] ;then
##Allow for base-index configuration
base_index=0
if [ -f ~/.tmux.conf ] ;then
if grep -v ^# ~/.tmux.conf | egrep 'base-index +[0-9]' >/dev/null ;then
base_index=$(grep -v ^# ~/.tmux.conf | egrep 'base-index +[0-9]' | awk -F'base-index ' '{print $2}')
fi
fi
##Check for specified number backup. If none, then use latest.
if [ "${backup_number}" != '' ] ;then
backup_dir=${backup_dir}.${backup_number}
fi
##Restore proper number of sessions, windows, and panes
for session in $(ls ${backup_dir} | grep -v '\.size$' | cut -d: -f1 | sort -du) ;do
window_list=$(ls ${backup_dir} | awk -F: '/^'${session}':/ {print $2}' | cut -d\. -f1 | sort -nu)
window_list_rev=$(echo "${window_list}" | sort -nr)
num_windows=$(echo ${window_list} | wc -w)
##create session, and first window.
echo "* Creating new session, \"${session}\"..."
session_width=$(cut -d x -f 1 ${backup_dir}/${session}.size)
session_height=$(($(cut -d x -f 2 ${backup_dir}/${session}.size)+1))
tmux new-session -d -s ${session} -x ${session_width} -y ${session_height}
##create additional windows if # of windows is > 1
if [ ${num_windows} -gt 1 ] ;then
echo "* Creating $((${num_windows}-1)) additional windows for session, \"${session}\"..."
i=1
while [ ${i} -lt ${num_windows} ] ;do
tmux new-window -d -a -t ${session}:${base_index}
i=$((${i}+1))
done
fi
##re-number the windows to reflect backed-up window number
echo "* Re-numbering windows to reflect original scheme:"
#always get $i to 1 regardless of base-index
i=$((${num_windows}+(${base_index}-1)))
for window in ${window_list_rev} ;do
if [ ${i} -ne ${window} ] ;then
echo "${session}:${i} -> ${session}:${window}"
tmux move-window -d -s ${session}:${i} -t ${session}:${window}
fi
i=$((${i}-1))
done
##if windows had multiple panes, populate with proper number of panes
for window in ${window_list} ;do
pane_list=$(ls ${backup_dir} | grep -v 'layout$' | awk -F\. '/^'${session}':'${window}'\./ {print $2}')
num_panes=$(echo ${pane_list} | wc -w)
if [ ${num_panes} -gt 1 ] ;then
echo "* Adding panes to window, \"${session}:${window}\"."
i=1
while [ ${i} -lt ${num_panes} ] ;do
tmux split-window -d -v -t ${session}:${window}.0
rval=${?}
if [ ${rval} -gt 0 ] ;then
echo "Error on split-window with \"${session}:${window}\", compensating by re-arranging panes and trying aga
in."
tmux select-layout -t ${session}:${window} tiled
tmux split-window -d -v -t ${session}:${window}.0
fi
i=$((${i}+1))
done
echo "Applying saved layout to panes in window, \"${session}:${window}\"."
layout=$(cat ${backup_dir}/${session}:${window}.layout)
tmux select-layout -t ${session}:${window} "${layout}"
for pane in ${pane_list} ;do
pane_full="${session}:${window}.${pane}"
tmux send-keys -t ${pane_full} "cat ${backup_dir}/${pane_full}
" #carriage return from previous line
mimic_state
done
else
pane_full="${session}:${window}.0"
tmux send-keys -t ${pane_full} "grep -v -e 'strings you dont want to see' -e 'another string you dont want to se
e' ${backup_dir}/${pane_full} | cat -s
" #carriage return from previous line
mimic_state
fi
done
done
fi