Add misc stuff
[misc.git] / bin / tm
1 #!/bin/bash
2
3 # Copyright (C) 2011, 2012, 2013, 2014, 2016 Joerg Jaspert <joerg@debian.org>
4 #
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions
7 # are met:
8 # .
9 # 1. Redistributions of source code must retain the above copyright
10 # notice, this list of conditions and the following disclaimer.
11 # 2. Redistributions in binary form must reproduce the above copyright
12 # notice, this list of conditions and the following disclaimer in the
13 # documentation and/or other materials provided with the distribution.
14 # .
15 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
26 # Always exit on errors
27 set -e
28 # Undefined variables, we don't like you
29 set -u
30 # ERR traps are inherited by shell functions, command substitutions and
31 # commands executed in a subshell environment.
32 set -E
33
34 ########################################################################
35 # The following variables can be overwritten outside the script.
36 #
37
38 # We want a useful tmpdir, so set one if it isn't already. Thats the
39 # place where tmux puts its socket, so you want to ensure it doesn't
40 # change under your feet - like for those with a daily-changing tmpdir
41 # in their home...
42 declare -r TMPDIR=${TMPDIR:-"/tmp"}
43
44 # Do you want me to sort the arguments when opening an ssh/multi-ssh session?
45 # The only use of the sorted list is for the session name, to allow you to
46 # get the same session again no matter how you order the hosts on commandline.
47 declare -r TMSORT=${TMSORT:-"true"}
48
49 # Want some extra options given to tmux? Define TMOPTS in your environment.
50 # Note, this is only used in the final tmux call where we actually
51 # attach to the session!
52 TMOPTS=${TMOPTS:-"-2"}
53
54 # The following directory can hold session config for us, so you can use them
55 # as a shortcut.
56 declare -r TMDIR=${TMDIR:-"${HOME}/.tmux.d"}
57
58 # Should we prepend the hostname to autogenerated session names?
59 # Example: Call tm ms host1 host2.
60 # TMSESSHOST=true -> session name is HOSTNAME_host1_host2
61 # TMSESSHOST=false -> session name is host1_host2
62 declare -r TMSESSHOST=${TMSESSHOST:-"true"}
63
64 # Allow to globally define a custom ssh command line.
65 TMSSHCMD=${TMSSHCMD:-"ssh"}
66
67 # Debug output
68 declare -r DEBUG=${DEBUG:-"false"}
69
70 # Save the last argument, it may be used (traditional style) for
71 # replacing
72 args=$#
73 TMREPARG=${!args}
74
75 # Where does your tmux starts numbering its windows? Mine does at 1,
76 # default for tmux is 0. We try to find it out, but if we fail, (as we
77 # only check $HOME/.tmux.conf you can set this variable to whatever it
78 # is for your environment.
79 if [[ -f ${HOME}/.tmux.conf ]]; then
80 bindex=$(grep ' base-index ' ${HOME}/.tmux.conf || echo 0 )
81 bindex=${bindex//* }
82 else
83 bindex=0
84 fi
85 declare TMWIN=${TMWIN:-$bindex}
86 unset bindex
87
88 ########################################################################
89 # Nothing below here to configure
90
91 # Should we group the session to another? Set to true if -g on
92 # commandline
93 GROUPSESSION=false
94
95 # Should we open another session, even if we already have one with
96 # this name? (Ie. second multisession to the same set of hosts)
97 # This is either set by the getopts option -n or by having -n
98 # as very first parameter after the tm command
99 if [[ $# -ge 1 ]] && [[ "${1}" = "-n" ]]; then
100 DOUBLENAME=true
101 # And now get rid of it. getopts won't see it, as it was first and
102 # we remove it - but it doesn't matter, we set it already.
103 # getopts is only used if it appears somewhere else in the
104 # commandline
105 shift
106 else
107 DOUBLENAME=false
108 fi
109
110 # Store the first commandline parameter
111 cmdline=${1:-""}
112
113 # Get the tmux version and split it in major/minor
114 TMUXVERS=$(tmux -V 2>/dev/null || echo "tmux 1.3")
115 declare -r TMUXVERS=${TMUXVERS##* }
116 declare -r TMUXMAJOR=${TMUXVERS%%.*}
117 declare -r TMUXMINOR=${TMUXVERS##*.}
118
119 # Save IFS
120 declare -r OLDIFS=${IFS}
121
122 # To save session file data
123 TMDATA=""
124
125 # Freeform .cfg file or other session file?
126 TMSESCFG=""
127
128 ########################################################################
129 function usage() {
130 echo "tmux helper by Joerg Jaspert <joerg@ganneff.de>"
131 echo "There are two ways to call it. Traditional and \"getopts\" style."
132 echo "Traditional call as: $0 CMD [host]...[host]"
133 echo "Getopts call as: $0 [-s host] [-m hostlist] [-k name] [-l] [-n] [-h] [-c config] [-e]"
134 echo "Note that traditional and getopts can be mixed, sometimes."
135 echo ""
136 echo "Traditional:"
137 echo "CMD is one of"
138 echo " ls List running sessions"
139 echo " s Open ssh session to host"
140 echo " ms Open multi ssh sessions to hosts, synchronizing input"
141 echo " To open a second session to the same set of hosts put a"
142 echo " -n in front of ms"
143 echo " k Kill a session. Note that this needs the exact session name"
144 echo " as shown by tm ls"
145 echo " \$anything Either plain tmux session with name of \$anything or"
146 echo " session according to TMDIR file"
147 echo ""
148 echo "Getopts style:"
149 echo "-l List running sessions"
150 echo "-s host Open ssh session to host"
151 echo "-m hostlist Open multi ssh sessions to hosts, synchronizing input"
152 echo " Due to the way getopts works, hostlist must be enclosed in \"\""
153 echo "-n Open a second session to the same set of hosts"
154 echo "-g Group session - attach to an existing session, but keep seperate"
155 echo " window control"
156 echo "-k name Kill a session. Note that this needs the exact session name"
157 echo " as shown by tm ls"
158 echo "-c config Setup session according to TMDIR file"
159 echo "-e SESSION Use existion session named SESSION"
160 echo "-r REPLACE Value to use for replacing in session files"
161 echo ""
162 echo "TMDIR file:"
163 echo "Each file in \$TMDIR defines a tmux session. There are two types of files,"
164 echo "those without an extension and those with the extension \".cfg\" (no \"\")."
165 echo "The filename corresponds to the commandline \$anything (or -c)."
166 echo ""
167 echo "Content of extensionless files is defined as:"
168 echo " First line: Session name"
169 echo " Second line: extra tmux commandline options"
170 echo " Any following line: A hostname to open a shell with in the normal"
171 echo " ssh syntax. (ie [user@]hostname)"
172 echo ""
173 echo "Content of .cfg files is defined as:"
174 echo " First line: Session name"
175 echo " Second line: extra tmux commandline options"
176 echo " Third line: The new-session command to use. Place NONE here if you want plain"
177 echo " defaults, though that may mean just a shell. Otherwise put the full"
178 echo " new-session command with all options you want here."
179 echo " Any following line: Any tmux command you can find in the tmux manpage."
180 echo " You should ensure that commands arrive at the right tmux session / window."
181 echo " To help you with this, there are some variables available which you"
182 echo " can use, they are replaced with values right before commands are executed:"
183 echo " SESSION - replaced with the session name"
184 echo " TMWIN - see below for explanation of TMWIN Environment variable"
185 echo ""
186 echo "NOTE: Both types of files accept external listings of hostnames."
187 echo " That is, the output of any shell command given will be used as a list"
188 echo " of hostnames to connect to (or a set of tmux commands to run)."
189 echo ""
190 echo "NOTE: Session files can include the Token ++TMREPLACETM++ at any point. This"
191 echo " will be replaced by the value of the -r option (if you use getopts style) or"
192 echo " by the LAST argument on the line if you use traditional calling."
193 echo " Note that with traditional calling, the argument will also be tried as a hostname,"
194 echo " so it may not make much sense there, unless using a session file that contains"
195 echo " solely of LIST commands."
196 echo ""
197 echo "NOTE: Session files can include any existing environment variable at any point (but"
198 echo " only one per line). Those get replaced during tm execution time with the actual"
199 echo " value of the environment variable. Common usage is $HOME, but any existing var"
200 echo " works fine."
201 echo ""
202 echo "Environment variables recognized by this script:"
203 echo "TMPDIR - Where tmux stores its session information"
204 echo " DEFAULT: If unset: /tmp"
205 echo "TMSORT - Should ms sort the hostnames, so it always opens the same"
206 echo " session, no matter in which order hostnames are presented"
207 echo " DEFAULT: true"
208 echo "TMOPTS - Extra options to give to the tmux call"
209 echo " Note that this ONLY affects the final tmux call to attach"
210 echo " to the session, not to the earlier ones creating it"
211 echo " DEFAULT: -2"
212 echo "TMDIR - Where are session information files stored"
213 echo " DEFAULT: ${HOME}/.tmux.d"
214 echo "TMWIN - Where does your tmux starts numbering its windows?"
215 echo " This script tries to find the information in your config,"
216 echo " but as it only checks $HOME/.tmux.conf it might fail".
217 echo " So if your window numbers start at anything different to 0,"
218 echo " like mine do at 1, then you can set TMWIN to 1"
219 echo "TMSESSHOST - Should the hostname appear in session names?"
220 echo " DEFAULT: true"
221 echo "TMSSHCMD - Allow to globally define a custom ssh command line."
222 echo " This can be just the command or any option one wishes to have"
223 echo " everywhere."
224 echo " DEFAULT: ssh"
225 echo "DEBUG - Show debug output (remember to redirect it to a file)"
226 echo ""
227 exit 42
228 }
229
230 # Simple "cleanup" of a variable, removing space and dots as we don't
231 # want them in our tmux session name
232 function clean_session() {
233 local toclean=${*:-""}
234
235 # Neither space nor dot nor : or " are friends in the SESSION name
236 toclean=${toclean// /_}
237 toclean=${toclean//:/_}
238 toclean=${toclean//\"/}
239 echo ${toclean//./_}
240 }
241
242 # Merge the commandline parameters (hosts) into a usable session name
243 # for tmux
244 function ssh_sessname() {
245 if [[ ${TMSORT} = true ]]; then
246 local one=$1
247 # get rid of first argument (s|ms), we don't want to sort this
248 shift
249 local sess=$(for i in $@; do echo $i; done | sort | tr '\n' ' ')
250 sess="${one} ${sess% *}"
251 else
252 # no sorting wanted
253 local sess="${*}"
254 fi
255 clean_session ${sess}
256 }
257
258 # Setup functions for all tmux commands
259 function setup_command_aliases() {
260 local command
261 local SESNAME
262 SESNAME="tmlscm$$"
263 if [[ ${TMUXMAJOR} -lt 2 ]] || [[ ${TMUXMINOR} -lt 2 ]]; then
264 # Starting tmux 2.2, this is no longer needed
265 # Debian Bug #718777 - tmux needs a session to have lscm work
266 tmux new-session -d -s ${SESNAME} -n "check" "sleep 3"
267 fi
268 for command in $(tmux list-commands|awk '{print $1}'); do
269 eval "tm_$command() { tmux $command \"\$@\" >/dev/null; }"
270 done
271 if [[ ${TMUXMAJOR} -lt 2 ]] || [[ ${TMUXMINOR} -lt 2 ]]; then
272 tmux kill-session -t ${SESNAME} || true
273 fi
274 }
275
276 # Run a command (function) after replacing variables
277 function do_cmd() {
278 local cmd=$*
279 cmd1=${cmd%% *}
280 if [[ ${cmd1} =~ ^# ]]; then
281 return
282 elif [[ ${cmd1} =~ new-window ]]; then
283 TMWIN=$(( TMWIN + 1 ))
284 fi
285
286 cmd=${cmd//SESSION/$SESSION}
287 cmd=${cmd//TMWIN/$TMWIN}
288 cmd=${cmd/$cmd1 /}
289 debug $cmd1 $cmd
290 eval tm_$cmd1 $cmd
291 }
292
293 # Use a configuration file to setup the tmux parameters/session
294 function own_config() {
295 if [[ ${1} =~ .cfg$ ]]; then
296 TMSESCFG="free"
297 fi
298 # Set IFS to be NEWLINE only, not also space/tab, as our input files
299 # are \n seperated (one entry per line) and lines may well have spaces.
300 local IFS="
301 "
302 # Fill an array with our config
303 if [[ -n ${TMDATA[@]:-""} ]] && [[ ${#TMDATA[@]} -gt 0 ]]; then
304 olddata=("${TMDATA[@]}")
305 fi
306
307 TMDATA=( $(sed -e "s/++TMREPLACETM++/${TMREPARG}/g" "${TMDIR}/$1") )
308 # Restore IFS
309 IFS=${OLDIFS}
310
311 SESSION=${SESSION:-$(clean_session ${TMDATA[0]})}
312
313 if [ "${TMDATA[1]}" != "NONE" ]; then
314 TMOPTS=${TMDATA[1]}
315 fi
316
317 # Seperate the lines we work with
318 local IFS=""
319 local -a workdata=(${TMDATA[@]:2})
320 IFS=${OLDIFS}
321
322 # Lines (starting with line 3) may start with LIST, then we get
323 # the list of hosts from elsewhere. So if one does, we exec the
324 # command given, then append the output to TMDATA - while deleting
325 # the actual line with LIST in.
326 local TMPDATA=$(mktemp -u -p ${TMPDIR} .tmux_tm_XXXXXXXXXX)
327 trap "rm -f ${TMPDATA}" EXIT ERR HUP INT QUIT TERM
328 local index=0
329 while [[ ${index} -lt ${#workdata[@]} ]]; do
330 if [[ "${workdata[${index}]}" =~ ^LIST\ (.*)$ ]]; then
331 # printf -- 'workdata: %s\n' "${workdata[@]}"
332 local cmd=${BASH_REMATCH[1]}
333 if [[ ${cmd} =~ \$\{([0-9a-zA-Z_]+)\} ]]; then
334 repvar=${BASH_REMATCH[1]}
335 reptext=${!repvar}
336 cmd=${cmd//\$\{$repvar\}/$reptext}
337 fi
338 echo "Line ${index}: Fetching hostnames using provided shell command '${cmd}', please stand by..."
339
340 $( ${cmd} >| "${TMPDATA}" )
341 # Set IFS to be NEWLINE only, not also space/tab, the list may have ssh options
342 # and what not, so \n is our seperator, not more.
343 IFS="
344 "
345 out=( $(tr -d '\r' < "${TMPDATA}" ) )
346
347 # Restore IFS
348 IFS=${OLDIFS}
349
350 workdata+=( "${out[@]}" )
351 unset workdata[${index}]
352 unset out
353 # printf -- 'workdata: %s\n' "${workdata[@]}"
354 elif [[ "${workdata[${index}]}" =~ ^SSHCMD\ (.*)$ ]]; then
355 TMSSHCMD=${BASH_REMATCH[1]}
356 fi
357 index=$(( index + 1 ))
358 done
359 rm -f "${TMPDATA}"
360 trap - EXIT ERR HUP INT QUIT TERM
361 debug "TMDATA: ${TMDATA[@]}"
362 debug "olddata: ${olddata[@]:-''}"
363 if [[ -n ${olddata[@]:-""} ]]; then
364 TMDATA=( "${olddata[@]}" "${workdata[@]}" )
365 else
366 TMDATA=( "${TMDATA[@]:0:2}" "${workdata[@]}" )
367 fi
368 declare -r TMDATA=( "${TMDATA[@]}" )
369 debug "TMDATA now ${TMDATA[@]}"
370 }
371
372 # Simple overview of running sessions
373 function list_sessions() {
374 local IFS=""
375 if output=$(tmux list-sessions 2>/dev/null); then
376 echo $output
377 else
378 echo "No tmux sessions available"
379 fi
380 }
381
382 # We either have a debug function that shows output, or one that
383 # plainly returns
384 if [[ ${DEBUG} == true ]]; then
385 eval "debug() { >&2 echo \$* ; }"
386 else
387 eval "debug() { return ; }"
388 fi
389
390 setup_command_aliases
391
392 ########################################################################
393 # MAIN work follows here
394 # Check the first cmdline parameter, we might want to prepare something
395 case ${cmdline} in
396 ls)
397 list_sessions
398 exit 0
399 ;;
400 s|ms|k)
401 # Yay, we want ssh to a remote host - or even a multi session setup - or kill one
402 # So we have to prepare our session name to fit in what tmux (and shell)
403 # allow us to have. And so that we can reopen an existing session, if called
404 # with the same hosts again.
405 SESSION=$(ssh_sessname $@)
406 declare -r cmdline
407 shift
408 ;;
409 -*)
410 while getopts "lnhs:m:c:e:r:k:g:" OPTION; do
411 case ${OPTION} in
412 l) # ls
413 list_sessions
414 exit 0
415 ;;
416 s) # ssh
417 SESSION=$(ssh_sessname s ${OPTARG})
418 declare -r cmdline=s
419 shift
420 ;;
421 k) # kill session
422 SESSION=$(ssh_sessname s ${OPTARG})
423 declare -r cmdline=k
424 shift
425 ;;
426 m) # ms (needs hostnames in "")
427 SESSION=$(ssh_sessname ms ${OPTARG})
428 declare -r cmdline=ms
429 shift
430 ;;
431 c) # pre-defined config
432 own_config ${OPTARG}
433 ;;
434 e) # existing session name
435 SESSION=$(clean_session ${OPTARG})
436 shift
437 ;;
438 n) # new session even if same name one already exists
439 DOUBLENAME=true
440 ;;
441 r) # replacement arg
442 TMREPARG=${OPTARG}
443 ;;
444 g) # Group session, not simple attach
445 declare -r GROUPSESSION=true
446 SESSION=$(clean_session ${OPTARG})
447 shift
448 ;;
449 h)
450 usage
451 ;;
452 esac
453 done
454 ;;
455 *)
456 # Nothing special (or something in our tmux.d)
457 if [ $# -lt 1 ]; then
458 SESSION=${SESSION:-""}
459 if [[ -n "${SESSION}" ]]; then
460 # Environment has SESSION set, wherever from. So lets
461 # see if its an actual tmux session
462 if ! tmux has-session -t "${SESSION}" 2>/dev/null; then
463 # It is not. And no argument. Show usage
464 usage
465 fi
466 else
467 usage
468 fi
469 elif [ -r "${TMDIR}/${cmdline}" ]; then
470 for arg in "$@"; do
471 own_config ${arg}
472 done
473 else
474 # Not a config file, so just session name.
475 SESSION=${cmdline}
476 fi
477 ;;
478 esac
479
480 havesession="false"
481 if tmux has-session -t ${SESSION} 2>/dev/null; then
482 havesession="true"
483 fi
484 declare -r havesession
485
486 # And now check if we would end up with a doubled session name.
487 # If so add something "random" to the new name, like our pid.
488 if [[ ${DOUBLENAME} == true ]] && [[ ${havesession} == true ]]; then
489 # Session exist but we are asked to open another one,
490 # so adjust our session name
491 if [[ ${#TMDATA} -eq 0 ]] && [[ ${SESSION} =~ ([ms]+)_(.*) ]]; then
492 SESSION="${BASH_REMATCH[1]}_$$_${BASH_REMATCH[2]}"
493 else
494 SESSION="$$_${SESSION}"
495 fi
496 fi
497
498 if [[ ${TMSESSHOST} = true ]]; then
499 declare -r SESSION="$(uname -n|cut -d. -f1)_${SESSION}"
500 else
501 declare -r SESSION
502 fi
503
504 # We only do special work if the SESSION does not already exist.
505 if [[ ${cmdline} != k ]] && [[ ${havesession} == false ]]; then
506 # In case we want some extra things...
507 # Check stupid users
508 if [ $# -lt 1 ]; then
509 usage
510 fi
511 tm_pane_error="create pane failed: pane too small"
512 case ${cmdline} in
513 s)
514 # The user wants to open ssh to one or more hosts
515 do_cmd new-session -d -s ${SESSION} -n "${1}" "'${TMSSHCMD} ${1}'"
516 # We disable any automated renaming, as that lets tmux set
517 # the pane title to the process running in the pane. Which
518 # means you can end up with tons of "bash". With this
519 # disabled you will have panes named after the host.
520 do_cmd set-window-option -t ${SESSION} automatic-rename off >/dev/null
521 # If we have at least tmux 1.7, allow-rename works, such also disabling
522 # any rename based on shell escape codes.
523 if [ ${TMUXMINOR//[!0-9]/} -ge 7 ] || [ ${TMUXMAJOR//[!0-9]/} -gt 1 ]; then
524 do_cmd set-window-option -t ${SESSION} allow-rename off >/dev/null
525 fi
526 shift
527 count=2
528 while [ $# -gt 0 ]; do
529 do_cmd new-window -d -t ${SESSION}:${count} -n "${1}" "${TMSSHCMD} ${1}"
530 do_cmd set-window-option -t ${SESSION}:${count} automatic-rename off >/dev/null
531 # If we have at least tmux 1.7, allow-rename works, such also disabling
532 # any rename based on shell escape codes.
533 if [ ${TMUXMINOR//[!0-9]/} -ge 7 ] || [ ${TMUXMAJOR//[!0-9]/} -gt 1 ]; then
534 do_cmd set-window-option -t ${SESSION}:${count} allow-rename off >/dev/null
535 fi
536 count=$(( count + 1 ))
537 shift
538 done
539 ;;
540 ms)
541 # We open a multisession window. That is, we tile the window as many times
542 # as we have hosts, display them all and have the user input send to all
543 # of them at once.
544 do_cmd new-session -d -s ${SESSION} -n "Multisession" "'${TMSSHCMD} ${1}'"
545 shift
546 while [ $# -gt 0 ]; do
547 set +e
548 output=$(do_cmd split-window -d -t ${SESSION}:${TMWIN} "'${TMSSHCMD} ${1}'" 2>&1)
549 ret=$?
550 set -e
551 if [[ ${ret} -ne 0 ]] && [[ ${output} == ${tm_pane_error} ]]; then
552 # No more space -> have tmux redo the
553 # layout, so all windows are evenly sized.
554 do_cmd select-layout -t ${SESSION}:${TMWIN} main-horizontal >/dev/null
555 # And dont shift parameter away
556 continue
557 fi
558 shift
559 done
560 # Now synchronize them
561 do_cmd set-window-option -t ${SESSION}:${TMWIN} synchronize-pane >/dev/null
562 # And set a final layout which ensures they all have about the same size
563 do_cmd select-layout -t ${SESSION}:${TMWIN} tiled >/dev/null
564 ;;
565 *)
566 # Whatever string, so either a plain session or something from our tmux.d
567 if [ -z "${TMDATA}" ]; then
568 # the easy case, just a plain session name
569 do_cmd new-session -d -s ${SESSION}
570 else
571 # data in our data array, the user wants his own config
572 if [[ ${TMSESCFG} = free ]]; then
573 if [[ ${TMDATA[2]} = NONE ]]; then
574 # We have a free form config where we get the actual tmux commands
575 # supplied by the user, so just issue them after creating the session.
576 do_cmd new-session -d -s ${SESSION} -n "'${TMDATA[0]}'"
577 else
578 do_cmd ${TMDATA[2]}
579 fi
580 tmcount=${#TMDATA[@]}
581 index=3
582 while [ ${index} -lt ${tmcount} ]; do
583 do_cmd ${TMDATA[$index]}
584 (( index++ ))
585 done
586 else
587 # So lets start with the "first" line, before dropping into a loop
588 do_cmd new-session -d -s ${SESSION} -n "${TMDATA[0]}" "'${TMSSHCMD} ${TMDATA[2]}'"
589
590 tmcount=${#TMDATA[@]}
591 index=3
592 while [ ${index} -lt ${tmcount} ]; do
593 # List of hostnames, open a new connection per line
594 set +e
595 output=$(do_cmd split-window -d -t ${SESSION}:${TMWIN} "'${TMSSHCMD} ${TMDATA[$index]}'" 2>&1)
596 set -e
597 if [[ ${output} =~ ${tm_pane_error} ]]; then
598 # No more space -> have tmux redo the
599 # layout, so all windows are evenly sized.
600 do_cmd select-layout -t ${SESSION}:${TMWIN} main-horizontal >/dev/null
601 # And again, don't increase index
602 continue
603 fi
604 (( index++ ))
605 done
606 # Now synchronize them
607 do_cmd set-window-option -t ${SESSION}:${TMWIN} synchronize-pane >/dev/null
608 # And set a final layout which ensures they all have about the same size
609 do_cmd select-layout -t ${SESSION}:${TMWIN} tiled >/dev/null
610 fi
611 fi
612 ;;
613 esac
614 # Build up new session, ensure we start in the first window
615 do_cmd select-window -t ${SESSION}:${TMWIN}
616 elif [[ ${cmdline} == k ]]; then
617 # So we are asked to kill a session
618 tokill=${SESSION//k_/}
619 do_cmd kill-session -t ${tokill}
620 exit 0
621 fi
622
623 # If we should group our session or not
624 if [[ ${GROUPSESSION} == true ]]; then
625 # Grouping means opening a new session, but sharing the sessions with
626 # another session (existing and new windows). But window control is separate.
627 sesname="$$_${SESSION}"
628 tmux ${TMOPTS} new-session -s ${sesname} -t ${SESSION}
629 tmux ${TMOPTS} kill-session -t ${sesname}
630 else
631 # Do not group, just attach
632 tmux ${TMOPTS} attach -t ${SESSION}
633 fi