From e4537936f674d71afe96ee2f8a86dad6c3294409 Mon Sep 17 00:00:00 2001 From: Stefan Kreutz Date: Wed, 18 May 2022 22:12:39 +0200 Subject: Add initial implementation --- Makefile | 9 +++++++ README.md | 22 ++++++++++++++++ ssh-tmux.1 | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ssh-tmux.sh | 48 ++++++++++++++++++++++++++++++++++ 4 files changed, 165 insertions(+) create mode 100644 Makefile create mode 100644 README.md create mode 100644 ssh-tmux.1 create mode 100755 ssh-tmux.sh diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..7736f8b --- /dev/null +++ b/Makefile @@ -0,0 +1,9 @@ +MAN= ssh-tmux.1 +BINDIR= /usr/local/bin +MANDIR= /usr/local/man/man + +beforeinstall: + ${INSTALL} ${INSTALL_COPY} -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \ + ${.CURDIR}/ssh-tmux.sh ${DESTDIR}${BINDIR}/ssh-tmux + +.include diff --git a/README.md b/README.md new file mode 100644 index 0000000..a9c9f21 --- /dev/null +++ b/README.md @@ -0,0 +1,22 @@ +# ssh-tmux + +The `ssh-tmux` utility executes a given command via `ssh` in a new `tmux` +session on a specified host. + +The intended purpose is to execute long-running interactive remote commands +with the ability to re-connect. See [this](https://www.skreutz.com/posts/TODO/) +blog post for an introduction, and refer to the man page for details. + +## Install + +Run `make install` as root to install the `ssh-tmux` utility and man page. + +## Release + +Create an annotated tag, and an archive as follows, replacing `0.1.0` with the +current version. + + $ git tag --annotate --message "Version 0.1.0" 0.1.0 + $ git archive --format=tar.gz --prefix=ssh-tmux-0.1.0/ \ + --output ssh-tmux-0.1.0.tar.gz 0.1.0 + diff --git a/ssh-tmux.1 b/ssh-tmux.1 new file mode 100644 index 0000000..ec62371 --- /dev/null +++ b/ssh-tmux.1 @@ -0,0 +1,86 @@ +.\" Copyright (c) 2022 Stefan Kreutz +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.Dd $Mdocdate: May 18 2022 $ +.Dt SSH-TMUX 1 +.Os +.Sh NAME +.Nm ssh-tmux +.Nd execute commands in remote tmux sessions +.Sh SYNOPSIS +.Nm ssh-tmux +.Op Fl d +.Op Fl s Ar session +.Op Fl n Ar window +.Ar host +.Ar command +.Op Ar argument ... +.Sh DESCRIPTION +The +.Nm +utility executes the given +.Ar command +via +.Xr ssh 1 +in a new +.Xr tmux 1 +session on the specified +.Ar host . +The +.Ar command +may have additional arguments. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl d +Detach from the +.Xr tmux 1 +session. +.It Fl s Ar session +The name of the +.Xr tmux 1 +session. +.It Fl n Ar window +The name of the +.Xr tmux 1 +window. +.El +.Sh EXIT STATUS +.Ex -std ssh-tmux +.Sh EXAMPLES +Execute a possibly long-running interactive remote command: +.Bd -literal -offset indent +$ ssh-tmux example.com "cd project && make && doas make install" +.Ed +.Pp +A command with local and remote shell expansion: +.Bd -literal -offset indent +$ ssh-tmux example.com echo $HOST \e$HOST +.Ed +.Pp +Detach and re-attach session: +.Bd -literal -offset indent +$ ssh-tmux -d -s monitor example.com top +$ ssh -t example.com tmux attach-session -t monitor +.Ed +.Pp +Move window to another session: +.Bd -literal -offset indent +$ ssh-tmux -d -s monitor -n top example.com top +$ ssh -t example.com "tmux new-session -A -s mysession \e; move-window -s monitor:top" +.Ed +.Sh SEE ALSO +.Xr ssh 1 , +.Xr tmux 1 +.Sh AUTHORS +.An Stefan Kreutz Aq Mt mail@skreutz.com diff --git a/ssh-tmux.sh b/ssh-tmux.sh new file mode 100755 index 0000000..a7a7bac --- /dev/null +++ b/ssh-tmux.sh @@ -0,0 +1,48 @@ +#! /bin/sh + +# Copyright (c) 2022 Stefan Kreutz +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +set -o errexit +set -o nounset + +err_exit() { + print -u2 -- "$*" + exit 1 +} + +while getopts :hds:n: option; do + case "$option" in + d) detach=true ;; + s) session="$OPTARG" ;; + n) window="$OPTARG" ;; + :) err_exit "missing argument for option -$OPTARG" ;; + ?) err_exit "illegal option: -$OPTARG" ;; + esac +done +shift $((OPTIND-1)) + +if [ $# -eq 0 ]; then + err_exit "missing host argument" +fi +host="$1" +shift + +if [ $# -eq 0 ]; then + err_exit "missing command argument" +fi + +cmd="\"\$SHELL\" -ilc 'trap '\''ret=\$? ; [ \$ret -eq 0 ] || print -u2 -- \"[exited with status \$ret]\" ; exec \"\$SHELL\"'\'' EXIT INT ; $*'" + +exec ssh -t "$host" -- tmux new-session ${detach:+-d} ${session:+-s \"$session\"} ${window:+-n \"$window\"} "$cmd" -- cgit v1.2.3