≡ Menu

Alarm clock: How To Set Timeout For A Shell Command

Q. How can I run a command called foo, and have it timeout / abort after 10 seconds under GNU/Linux running bash shell or script? How do I run command under an alarm clock?

A. You should able to use python / ruby / php or perl to set such timer. Shell do not have in built facility for timeout a command.

Perl program

Here is sample perl code:

perl -e 'alarm shift @ARGV; exec @ARGV' 5 foo arg1 arg2

You may define it as shell function:

alarm() { perl -e 'alarm shift; exec @ARGV' "$@"; }

And call it as follows (wait 20 seconds before alrming foo command:)

alarm 20 foo arg1

Sample shell script

You can use following shell script to set timeout for a command:

:
##########################################################################
# Shellscript:	timeout - set timeout for a command
# Author     :	Heiner Steven <heiner.steven@odn.de>
# Date       :	29.07.1999
# Category   :	File Utilities
# Requires   :	
# SCCS-Id.   :	@(#) timeout	1.3 03/03/18
##########################################################################
# Description
#    o	Runs a command, and terminates it (by sending a signal) after
#	a specified time period
#    o	This command first starts itself as a "watchdog" process in the
#	background, and then runs the specified command.
#	If the command did not terminate after the specified
#	number of seconds, the "watchdog" process will terminate
#	the command by sending a signal.
#
# Notes
#    o	Uses the internal command line argument "-p" to specify the
#	PID of the process to terminate after the timeout to the
#	"watchdog" process.
#    o	The "watchdog" process is invoked by the name "$0", so
#	"$0" must be a valid path to the script.
#    o	If this script runs in the environment of the login shell
#	(i.e. it was invoked using ". timeout command...") it will
#	terminate the login session.
##########################################################################
 
PN=`basename "$0"`			# Program name
VER='1.3'
 
TIMEOUT=5				# Default [seconds]
 
Usage () {
    echo >&2 "$PN - set timeout for a command, $VER
usage: $PN [-t timeout] command [argument ...]
     -t: timeout (in seconds, default is $TIMEOUT)"
    exit 1
}
 
Msg () {
    for MsgLine
    do echo "$PN: $MsgLine" >&2
    done
}
 
Fatal () { Msg "$@"; exit 1; }
 
while [ $# -gt 0 ]
do
    case "$1" in
	-p)	ParentPID=$2; shift;;	# Used internally!
	-t)	Timeout="$2"; shift;;
	--)	shift; break;;
	-h)	Usage;;
	-*)	Usage;;
	*)	break;;			# First file name
    esac
    shift
done
 
: ${Timeout:=$TIMEOUT}			# Set default [seconds]
 
if [ -z "$ParentPID" ]
then
    # This is the first invokation of this script.
    # Start "watchdog" process, and then run the command.
    [ $# -lt 1 ] && Fatal "please specify a command to execute"
    "$0" -p $$ -t $Timeout &		# Start watchdog
    #echo >&2 "DEBUG: process id is $$"
    exec "$@"				# Run command
    exit 2				# NOT REACHED
else
    # We run in "watchdog" mode, $ParentPID contains the PID
    # of the process we should terminate after $Timeout seconds.
    [ $# -ne 0 ] && Fatal "please do not use -p option interactively"
 
    #echo >&2 "DEBUG: $$: parent PID to terminate is $ParentPID"
 
    exec >/dev/null 0<&1 2>&1	# Suppress error messages
    sleep $Timeout
    kill $ParentPID &&			# Give process time to terminate
    	(sleep 2; kill -1 $ParentPID) &&
	(sleep 2; kill -9 $ParentPID)
    exit 0
fi

(Credit: Heiner Steven)

doalarm c program

Download doalarm program:
$ wget http://pilcrow.madison.wi.us/sw/doalarm-0.1.7.tgz
Untar program:
$ tar -zxvf doalarm-0.1.7.tg
Compile doalarm:
$ cd doalarm-0.1.7
$ make
$ ./doalarm

Sample output:

Error: missing required parameter
Usage: doalarm [-hr] [-t type] sec command [arg...]
Run command under an alarm clock.
Options:
 -t          Type of timer: 'real' (SIGALRM), 'virtual' (SIGVTALRM),
    --timer= 'profile' (SIGPROF), 'cpu' (SIGXCPU).  Default 'real'.
 -r --recur        Recurring alarm, every sec seconds.
 -h --help         Show help text (this message).
    --version      Display version.
doalarm 0.1.7 (14 Dec 2001)

Run foo as follows:
$ doalarm 20 foo

Tweet itFacebook itGoogle+ itPDF itFound an error/typo on this page?

{ 16 comments… add one }

  • Professor Fapsanders October 3, 2008, 5:37 pm

    You can also do it with bash using sleep and job control:
    $ foo & sleep 10 && kill %1 && fg

  • Jadu Saikia January 15, 2009, 10:16 am

    Good one, I have to download and use it. Thanks.

    The tip from Professor Fapsanders is also useful, we can make it more significant to kill the last background process by this:

    $ sh foo & sleep 5 && kill $! && fg

    // Jadu, unstableme.blogspot.com

    • Fred August 25, 2010, 8:51 am

      Great, thanks!

  • Riccardo Murri February 25, 2009, 2:15 pm

    Warning: the tip from Professor Fapsanders only works if “foo” does not require any input (background processes cannot do that).

    For the general case, you need to background the alarm process instead, as the sample “timeout” script does.

    • Linus September 30, 2010, 4:23 pm

      $ sh foo & sleep 5 && kill $! & fg ### (note the last “&” is not “&&”, so you foreground the job immediately)

  • Muhammad July 7, 2009, 8:05 pm

    How can i suppress the stupid ‘alarm clock’ output when the timeout expires?
    I’m running “perl -e ‘alarm shift @ARGV; exec @ARGV’ 5 cat” it terminates the cat command after 4 seconds but then i get stupid ‘Alarm clock’ output on the screen. I have to use this command in a shell script and i don’t want this output.

    I have tried redirecting standard error and std out but if i specify >/dev/null at the end of cat command, it redirects ‘cat”s output not from perl -e….. Any ideas? Thanks a lot

  • Peter July 13, 2009, 10:59 am

    Yup,
    you can redirect the error output to stdout:
    append ” >/dev/null 2>&1″ to the command

    • Vikrat January 21, 2012, 3:04 am

      even m facing the error, in the code below

      #include
      #include
      #include
      using namespace std;
      void onAlarm(int a)
      {
      cout<<"Alarm Buzzz\n";
      sleep(2);
      exit(0);
      }
      int main()
      {
      signal(SIGALRM, onAlarm);
      cout<<"enter\n";
      alarm(3);
      execl("./sant/a.out","./a.out",(char*)0);
      }

      if the file a.out has a sleep of say 10 seconds
      then it wont execute the onAlarm() function, instead it would just show Alarm clock
      can u help?

  • Muhammad July 13, 2009, 2:01 pm

    Thanks Peter.

    But the problem is appending >/dev/null 2>&1 to the command redirects stdout and stderr for the “command” not for the perl. So even by appending this to the command i still get “Alarm Clock” after command terminates.

    For example perl -e ‘alarm shift @ARGV; exec @ARGV’ 5 foo arg1 arg2 > /dev/null 2>&1 ‘ will redirect output and stderr from ‘foo’ command not from the alarm command.
    Thanks

  • Peter July 14, 2009, 6:22 am

    hey, you’re right… that’s funny.
    I tried to dig some deeper using strace and funnily it does not show up then:

    strace perl -e “alarm shift @ARGV; exec @ARGV” 5 cat >/dev/null 2>&1

    interesting issue, I do lack enough time to investigate
    regards

  • Cybergavin November 17, 2009, 6:27 pm

    Thanks. Using the perl snippet is neat. Pretty much all UNIX systems come with bash and perl. So, this is cool.

  • Chris January 22, 2010, 9:37 pm

    Thanks, the doalarm program worked very nicely for my purposes.

  • Pedro January 24, 2011, 4:12 am

    God bless you!

  • me February 12, 2011, 11:13 pm

    There is a command “timeout” in the latest Ubuntu Linux (10.10).

    Example:
    date; timeout 10m foo; date

    • Bill July 12, 2011, 5:42 pm

      Thanks, that works great!

  • Amar February 1, 2013, 6:56 am

    thanks a lot !

    the do alarm program works fine for me.

Leave a Comment