Skip to content

Instantly share code, notes, and snippets.

@smoser
Last active December 18, 2022 15:29
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save smoser/1019125 to your computer and use it in GitHub Desktop.
Save smoser/1019125 to your computer and use it in GitHub Desktop.
run a command in screen
#!/bin/sh
#
# upstream: git://gist.github.com/1019125.git
VERBOSITY=0
LOCK=""
CR="
"
error() { echo "$@" 1>&2; }
fail() { [ $# -eq 0 ] || error "$@"; exit 1; }
Usage() {
cat <<EOF
Usage: ${0##*/} [ options ] sess_name command
interact with gnu screen
${0##*/} provides a possibly simpler interface to interacting with screen.
options:
-c|--create create the session, fail if it exists
-X|--command pass command through to screen (-X)
-k|--keep-open keep the new window open after running command
-K|--keep-open-timeout TIME
keep window open for 'TIME' seconds after command
finishes
-t|--title TITLE create new window with title 'TITLE'
-v|--verbose increase verbosity
-p|--window WINDOW run in existing window 'WINDOW'
-q|--quit quit the session, closing all windows
fail if it does not exist
-R|--new-if-needed create a new session if 'sess_name' does not exist
-s|--stuff use "stuff" to execute command rather than 'screen'
requires --window.
-x|--kill kill a window (requires --window)
Example:
- create a new screen session (failing if it exists)
$ ${0##*/} mysession --create
- run a command via 'exec' in window 0
$ ${0##*/} mysession --window 0 ls
- create a new window and run a shell there with title 'newwin'
shell will close when exited
$ ${0##*/} mysession --title newwin /bin/bash
- stuff a string into 'newwin' (hopefully at at shell prompt)
$ ${0##*/} mysession --window newwin echo hi world
- forcefully kill the window 'newwin'
$ ${0##*/} mysession --window newwin --kill
- clean up, killing all processes and windows
$ ${0##*/} mysession --quit
EOF
}
bad_Usage() { Usage 1>&2; [ $# -eq 0 ] || error "$@"; exit 1; }
getlock() {
command -v lockfile-create >/dev/null || return 0
LOCK="$HOME/.${0##*/}.${session}" &&
lockfile-create --use-pid "$LOCK" &&
trap cleanlock EXIT ||
fail "failed to create lock"
}
cleanlock() {
[ -n "$LOCK" ] || return 0;
lockfile-remove "$LOCK" ||
{ error "WARN: removing lock failed: $LOCK"; LOCK=""; return 1; }
LOCK="";
}
short_opts="chkKp:qSst:Xx"
long_opts="command,create,help,quit,keep-open,keep-open-timeout:,kill,new-if-needed,stuff,title:,window:,verbose"
getopt_out=$(getopt --name "${0##*/}" \
--options "${short_opts}" --long "${long_opts}" -- "$@") &&
eval set -- "${getopt_out}" ||
bad_Usage
window=""
title=""
keep_open=false
ko_timeout=""
new_if_needed=false
lockfile=""
stuff=false
create=false
command=false
quit=false
kill=false
noargs_needed=false
rS="-r" # '-r' or '-S'. if creating a new session will be -S
while [ $# -ne 0 ]; do
cur=${1}; next=${2};
case "$cur" in
-X|--command) command=true;;
-c|--create) create=true; noargs_needed=true;;
-h|--help) Usage ; exit 0;;
-k|--keep-open) keep_open=true;;
-K|--keep-open-timeout) keep_open=true; ko_timeout=${2}; shift;;
-q|--quit) quit=true; noargs_needed=true;;
-R|--new-if-needed) new_if_needed=true;;
-s|--stuff) stuff=true;;
-t|--title) title=${2}; shift;;
-v|--verbose) VERBOSITY=$((${VERBOSITY}+1));;
-x|--kill) kill=true; noargs_needed=true;;
-p|--window) window=${2}; shift;;
--) shift; break;;
esac
shift;
done
[ $# -gt 0 ] || bad_Usage "must provide session"
session="${1}"
shift;
{ [ $# -gt 0 ] || $noargs_needed; } ||
bad_Usage "must provide screen session name and command"
[ -n "$window" ] && { "$keep_open" || [ -n "$title" ]; } &&
bad_Usage "--title and --keep-open are incompatible with --window"
$quit && [ $# -ne 0 ] &&
bad_Usage "args other than session name were given to quit"
if $kill; then
$create && fail "create and kill are incompatible"
$quit && fail "kill and quit are incompatible"
[ -n "$window" ] || fail "kill must have --window"
[ $# -eq 0 ] || fail "kill takes no arguments";
fi
if $quit; then
$create && fail "create and quit are incompatible"
[ $# -eq 0 ] || fail "quit takes no arguments";
fi
# get a lock to avoid a race between looking for session and creating it
getlock || fail "failed to get lock"
found=$(screen -ls | awk '-F\t' '$2 ~ m {print $2}' "m=[0-9]+[.]$session")
if [ -z "$found" ] && $quit; then
fail "failed to quit $session. not found"
elif [ -z "$found" ]; then
{ $create || $new_if_needed; } ||
fail "no session '$session' found. perhaps you want --new-if-needed"
rS="-S"
if [ -n "$window" ]; then
# if 'create' and 'window', create the window here, and execute in it below
screen -d -m -S "$session" -t "${window}"
rS="-r"
elif [ $# -eq 0 ]; then
screen -d -m -S "$session" ${title:+-t "${title}"}
exit
fi
elif $quit; then
screen -r "$session" -x -X quit || fail "failed to quit $session [$found]"
exit
elif $create; then
fail "create specified, but '$session' existed at '$found'"
fi
$create && [ $# -eq 0 ] && exit 0
if [ -n "$window" ]; then
if $stuff; then
screen $rS "$session" -x -p "$window" -X stuff "$*${CR}"
elif $kill; then
screen $rS "$session" -x -p "$window" -X kill
else
$command && cmd="" || cmd="exec"
screen $rS "$session" -x -p "$window" -X $cmd "$@"
fi
elif $keep_open; then
sh="sh"; read="read x"
[ -n "${ko_timeout}" ] &&
sh="bash" && read="read -t ${ko_timeout} x"
exec screen $rS "$session" -x -X screen ${title:+-t "${title}"} \
$sh -c '"$@"; echo Hit Enter to close; '"$read" inscreen-keepopen "$@"
else
cmd="screen"
$command && cmd=""
exec screen $rS "$session" -x -X $cmd ${title:+-t "${title}"} "$@"
fi
cleanlock || fail "failed to remove lock"
# vi: ts=4 noexpandtab
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment