Skip to content

Instantly share code, notes, and snippets.

@stephencroberts
Last active May 4, 2019 01:03
Show Gist options
  • Save stephencroberts/a96d63d1e297312c4f001d2388a1a10c to your computer and use it in GitHub Desktop.
Save stephencroberts/a96d63d1e297312c4f001d2388a1a10c to your computer and use it in GitHub Desktop.
Shell script to time a command with a timeout (POSIX compliant)
#!/bin/sh
#
# Time a command with a timeout
#
# Author: Stephen Roberts <stephenroberts@gmail.com>
# Version: 1
#
# Usage: twto [OPTIONS] TIMEOUT COMMAND
#
# Disable globbing
set -f
usage() {
printf "\nUsage: twto [OPTIONS] TIMEOUT COMMAND\n
Time a command with a timeout\n
Options:
-s, --timeout-success Exit 0 on timeout\n
Example: twto 60 ls\n"
}
err() {
printf "\e[31m[ERROR]\t%s\e[0m\n" "$2" >&2
exit "$1"
}
EXIT_NO_TIME=65
EXIT_TIMED_OUT=67
# Parse arguments
while [ $# -gt 0 ]; do
case "$1" in
-s|--timeout-success)
EXIT_TIMED_OUT=0
shift
;;
*)
POSITIONAL="$POSITIONAL $1"
shift
;;
esac
done
# shellcheck disable=SC2086
set -- $POSITIONAL
[ $# -lt 2 ] && usage && exit 0
TIMEOUT="$1"
shift
COMMAND="$*"
command -v /usr/bin/time >/dev/null || err "$EXIT_NO_TIME" \
"Command not found: /usr/bin/time"
# Create a named pipe
output=$(mktemp -u)
mkfifo -m 600 "$output"
# Time the command
# shellcheck disable=SC2086
( (/usr/bin/time -p $COMMAND>/dev/null) 2>"$output"
echo "done" >"$output" ) &
time_pid=$!
# Start timeout process
( trap 'kill -TERM $pid; exit 0' TERM
sleep "$TIMEOUT" &
pid=$!
wait $pid
echo timeout >"$output" ) &
sleep_pid=$!
# Trap exit to clean up
trap 'kill -0 "$time_pid" 1>/dev/null 2>&1'\
' && kill "$time_pid"'\
' && wait "$time_pid" 2>/dev/null;'\
'kill -0 "$sleep_pid" 1>/dev/null 2>&1'\
' && kill "$sleep_pid"'\
' && wait "$sleep_pid" 2>/dev/null;'\
'rm -f "$output"' EXIT
# Read from pipe until we see either "timeout" or "done"
while read -r line; do
if [ "$line" = "done" ]; then
exit 0
elif [ "$line" = "timeout" ]; then
echo "$TIMEOUT"
err "$EXIT_TIMED_OUT" "timed out"
elif test "${line#*real}" != "$line"; then
# shellcheck disable=SC2086
echo ${line#real}
exit 0
fi
done <"$output"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment