145

Is there an alternative for the timeout command on Mac OSx. The basic requirement is I am able to run a command for a specified amount of time.

e.g:

timeout 10 ping google.com

This program runs ping for 10s on Linux.

codeforester
  • 39,467
  • 16
  • 112
  • 140
sheki
  • 8,991
  • 13
  • 50
  • 69

6 Answers6

195

You can use

brew install coreutils

And then whenever you need timeout, use

gtimeout

..instead. To explain why here's a snippet from the Homebrew Caveats section:

Caveats

All commands have been installed with the prefix 'g'.

If you really need to use these commands with their normal names, you can add a "gnubin" directory to your PATH from your bashrc like:

PATH="/usr/local/opt/coreutils/libexec/gnubin:$PATH"

Additionally, you can access their man pages with normal names if you add the "gnuman" directory to your MANPATH from your bashrc as well:

MANPATH="/usr/local/opt/coreutils/libexec/gnuman:$MANPATH"
kvz
  • 5,517
  • 1
  • 42
  • 33
  • 31
    Then: alias timeout=gtimeout – nkadwa Mar 26 '15 at 19:33
  • 3
    Or `ln -s /usr/local/bin/gtimeout /usr/local/bin/timeout` to just enable the one command (the alias solution works for interactive CLI use, but not when called from bash scripts). – John Y Jan 30 '19 at 10:20
  • 2
    On my side after installed coerutils I got timeout available as time out: ln -s /usr/local/bin/gtimeout /usr/local/bin/timeout ln: /usr/local/bin/timeout: File exists – talsibony Sep 10 '20 at 09:57
  • 5
    Update: I just installed coreutils using `brew install coreutils`, and the `timeout` command was available without the prefix. – tdensmore Nov 06 '20 at 16:31
  • Great - but I'm nervous about introducing (and then forgetting) about dependencies. I prefer the perl solution since it's native. – Mark Jul 09 '21 at 13:28
35

Another simple approach that works pretty much cross platform (because it uses perl which is nearly everywhere) is this:

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

Snagged from here: https://gist.github.com/jaytaylor/6527607

Instead of putting it in a function, you can just put the following line in a script, and it'll work too:

timeout.sh

perl -e 'alarm shift; exec @ARGV' "$@";

or a version that has built in help/examples:

timeout.sh

#!/usr/bin/env bash

function show_help()
{
  IT=$(cat <<EOF

Runs a command, and times out if it doesnt complete in time

Example usage:
 
   # Will fail after 1 second, and shows non zero exit code result
   $ timeout 1 "sleep 2" 2> /dev/null ; echo \$?
   142

   # Will succeed, and return exit code of 0.
   $ timeout 1 sleep 0.5; echo \$?
   0

   $ timeout 1 bash -c 'echo "hi" && sleep 2 && echo "bye"' 2> /dev/null; echo \$?
   hi
   142

   $ timeout 3 bash -c 'echo "hi" && sleep 2 && echo "bye"' 2> /dev/null; echo \$?
   hi
   bye
   0
EOF
)
  echo "$IT"
  exit
}

if [ "$1" == "help" ]
then
  show_help
fi
if [ -z "$1" ]
then
  show_help
fi

#
# Mac OS-X does not come with the delightfully useful `timeout` program.  Thankfully a rough BASH equivalent can be achieved with only 2 perl statements.
#
# Originally found on SO: http://stackoverflow.com/questions/601543/command-line-command-to-auto-kill-a-command-after-a-certain-amount-of-time
# 
perl -e 'alarm shift; exec @ARGV' "$@";
Community
  • 1
  • 1
Brad Parks
  • 66,836
  • 64
  • 257
  • 336
  • What does it look like to use it directly, without wrapping it in a function? – mwfearnley Nov 08 '16 at 09:24
  • it's pretty much just remove the function and leave the perl line... I put more details above! – Brad Parks Nov 08 '16 at 12:59
  • What does it look like as a single-use one-liner? Something like `perl -e 'alarm shift; exec "ping google.com"`? – mwfearnley Nov 08 '16 at 16:04
  • Unfortunately this generates an `Alarm clock` message when the timer expires, and eliminating this [gets messy](https://unix.stackexchange.com/a/104918/17681). – RichVel Nov 16 '17 at 15:54
  • 1
    Hey... Did you try it like in the examples I showed? You can ignore the alarm clock message by running it like so: `./timeout.sh 1 "sleep 2.5" 2> /dev/null; echo $?`. Note that you can also capture the output if you're running it in a subshell like so: `RESULT=$(./timeout.sh 1 "sleep 2.5" 2> /dev/null; echo $?) ` – Brad Parks Nov 16 '17 at 23:17
  • 1
    Would be good to add the ualarm version for when you need more precision: `function timeout() { perl -e 'use Time::HiRes "ualarm"; ualarm shift; exec @ARGV' "$@"; }` (Note that it requires Perl >= 5.8 according to http://perldoc.perl.org/functions/alarm.html) – gib Apr 05 '18 at 11:28
  • @BradParks When I use this, I get an "Alarm clock" message output to `stderr`. Some quick searches suggest this is the shell's response to seeing a SIGALARM, not something that's actually output by `perl`. Any suggestions on how to suppress this (without ALSO suppressing all `stderr` from the script being run with a timeout)? – Jordan Jun 24 '22 at 02:43
23

As kvz stated simply use homebrew:

brew install coreutils

Now the timeout command is already ready to use - no aliases are required (and no gtimeout required, although also available).

jonashackt
  • 12,022
  • 5
  • 67
  • 124
10

You can limit execution time of any program using this command:

ping -t 10 google.com & sleep 5; kill $!
deadmoto
  • 482
  • 5
  • 8
  • 13
    This is probably not what you want. The result is that the command will run exactly 5 seconds. Meaning, if you want it to be a max time but not also the min this is not what you are looking for – gesell Feb 24 '15 at 15:34
  • I didn't understand what @gesell was saying at first. But after running this command: ` ping -t 1 google.com & sleep 5; kill $!` I realized what he/she meant: The _entire_ expression is going to take exactly 5 seconds before terminating. However, this is the solution I chose because I was running a bash command from a python program in background thread - so as long as it terminated sometime I was happy. – Mark Jul 09 '21 at 13:35
3

The Timeout Package from Ubuntu / Debian can be made to compile on Mac and it works. The package is available at http://packages.ubuntu.com/lucid/timeout

sheki
  • 8,991
  • 13
  • 50
  • 69
  • 4
    An easier way is to use Homebrew: `brew install coreutils` - then use `gtimeout` or set your PATH to use the `timeout` name. – RichVel Nov 16 '17 at 15:57
  • As of Ubuntu 20.04, there doesn't appear to be a separate `timeout` package. The `timeout` command is provided by `coreutils`. – Keith Thompson May 08 '21 at 06:09
1

You can do ping -t 10 google.com >nul

the >nul gets rid of the output. So instead of showing 64 BYTES FROM 123.45.67.8 BLAH BLAH BLAH it'll just show a blank newline until it times out. -t flag can be changed to any number.

redCube
  • 194
  • 1
  • 3
  • 4
    Ping was really a sample. I want to run a program to collect some metrics – sheki Aug 19 '10 at 08:23
  • 1
    `>nul` is a Windows thing. On macOS this would literally create a file called `nul` and redirect output to it – pxeger Jan 09 '22 at 06:41