#!/bin/bash
function usage {
echo "$(basename $0) [[user@]server:[port]] <screen-name> command..." >&2 exit 1
}
- [ $# -ge 2 ]
-
|| usage
SERVER= SERVERPORT=“-p 22” SERVERPAT=‘^((+@)?([A-Za-z0-9.]+)):(+)?$' if [[ “$1” =~ $SERVERPAT ]]; then
SERVER="${BASH_REMATCH[1]}" [[ -n "${BASH_REMATCH[4]}" ]] && SERVERPORT="-p ${BASH_REMATCH[4]}" shift
fi
function xscreen {
# Usage: xscreen <screen-name> command... local SCREEN_NAME=$1 shift if ! screen -list | grep $SCREEN_NAME >/dev/null ; then echo "Screen $SCREEN_NAME not found." >&2 return 124 # Create screen if it doesn't exist #screen -dmS $SCREEN_NAME fi # Create I/O pipes local DIR=$( mktemp -d ) mkfifo $DIR/stdin $DIR/stdout $DIR/stderr echo 123 > $DIR/status trap 'rm -f $DIR/{stdin,stdout,stderr,status}; rmdir $DIR' RETURN # Forward ^C to screen trap "screen -S $SCREEN_NAME -p0 -X stuff $'\003'" INT # Print output and kill stdin when both pipes are closed { cat $DIR/stderr >&2 & cat $DIR/stdout & wait [[ -e $DIR/stdin ]] && fuser -s -PIPE -k -w $DIR/stdin } & READER_PID=$! # Close all the pipes if the command fails to start (e.g. syntax error) { # Kill the sleep when this subshell is killed. Ugh.. bash. trap 'kill $(jobs -p)' EXIT # Try to write nothing to stdin. This will block until something reads. echo -n > $DIR/stdin & TEST_PID=$! sleep 2.0 # If the write failed and we're not killed, it probably didn't start if [[ -e $DIR/stdin ]] && kill $TEST_PID 2>/dev/null; then echo 'xscreen timeout' >&2 wait $TEST_PID 2>/dev/null # Send ^C to clear any half-written command (e.g. no closing braces) screen -S $SCREEN_NAME -p0 -X stuff $'\003' # Write nothing to output, triggers SIGPIPE echo -n 1> $DIR/stdout 2> $DIR/stderr # Stop stdin by creating a fake reader and sending SIGPIPE cat $DIR/stdin >/dev/null & fuser -s -PIPE -k -w $DIR/stdin fi } & CHECKER_PID=$! # Start the command (Clear line ^A^K, enter command with redirects, run with ^O) screen -S $SCREEN_NAME -p0 -X stuff "$(echo -ne '\001\013') { $* ; echo \$? > $DIR/status ; } <$DIR/stdin 1> >(tee $DIR/stdout) 2> >(tee $DIR/stderr >&2)$(echo -ne '\015')" # Forward stdin cat > $DIR/stdin kill $CHECKER_PID 2>/dev/null && wait $CHECKER_PID 2>/dev/null # Just in case stdin is closed early, wait for output to finish wait $READER_PID 2>/dev/null trap - INT return $(cat $DIR/status)
}
if [[ -n $SERVER ]]; then
ssh $SERVER $SERVERPORT "$(typeset -f xscreen); xscreen $@" RET=$? if [[ $RET == 124 ]]; then echo "To start screen: ssh $SERVER $SERVERPORT \"screen -dmS $1\"" >&2 fi exit $RET
else
xscreen "$1" "${@:2}"
fi