Reputation: 2115
I am working on a old Solaris node which does not have coreutils(timeout) tool installed. I am trying to print output of three bash commands separated by "-" x 80
chars. One of the command is having bad rep of taking very long time and I need to timeout that command and print the remaining output. I am trying to use alarm shift
but this does not help.
I need to keep the command as a one liner as I need to use this command in ansible's shell module. Can someone please help.
If I run the different CMDn
commands on bash terminal, it returns following output:
This is
from CMDn
Where n is 0 to 3.
When I run following perl command it returns :
perl -sanle 'BEGIN{$sep=("-"x80)."\n"; \
print "$sep $CMD0\n $sep $CMD1\n $sep $CMD2\n $sep $CMD2flt\n";exit}' \
-- -CMD0="$(CMD0)" -CMD1="$(CMD1 -q all)" -CMD2="$(CMD2)" -CMD2flt="$(CMD3)"
--------------------------------------------------------------------------------
This is
from CMD0
--------------------------------------------------------------------------------
This is
from CMD1
--------------------------------------------------------------------------------
This is
from CMD2
--------------------------------------------------------------------------------
This is
from CMD3
Sometimes, CMD3
takes very long time and I need to timeout it and proceed with the print of CMD0
, CMD1
, CMD2
. I tried this command but this does not help as it is not timing out and it will timeout for all the outputs. In this example I am using sleep 15 && CMD3
as CMD3 and timeout as 10 , but this does not helped. I followed this post Timeout command on Mac OS X?
perl -sanle 'BEGIN{alarm shift; $sep=("-"x80)."\n"; \
print "$sep $CMD0\n $sep $CMD1\n $sep $CMD2\n $sep $CMD2flt\n";exit}' \
-- -CMD0="$(CMD0)" -CMD1="$(CMD1 -q all)" -CMD2="$(CMD2)" -CMD2flt="$(sleep 15 && CMD3)" 10
Expecting following output if (for example) CMD3
is timing out.
--------------------------------------------------------------------------------
This is
from CMD0
--------------------------------------------------------------------------------
This is
from CMD1
--------------------------------------------------------------------------------
This is
from CMD2
--------------------------------------------------------------------------------
Null or blank or any intuitive text
Upvotes: 2
Views: 337
Reputation: 2115
I used following command to run list of commands with timeout value, when timeout command is not available. This command will ignore the error and move to next command in the array if any command time out. remove eval{ local $SIG{ALRM} = sub { die "Timeout\n" };
to fail the command if immediate fail is desired.
perl -sanle 'BEGIN{$sep=("-"x80)."\n";@cmds = ("CMD0", "CMD1", "CMD2", "sleep 5 && CMD3");foreach $cmd (@cmds) {eval{ local $SIG{ALRM} = sub { die "Timeout\n" }; alarm $timeout ;print $sep, qx{$cmd};alarm 0}; if($@){print "$cmd timed out"}};exit 0}' -- -timeout=30
Following command will fail if timeout is hit.
perl -sanle 'BEGIN{$sep=("-"x80)."\n";@cmds = ("CMD0", "CMD1", "CMD2", "sleep 5 && CMD3");foreach $cmd (@cmds) {eval{ alarm $timeout ;print $sep, qx{$cmd};alarm 0}; if($@){print "$cmd timed out"}};exit 0}' -- -timeout=30
In above commands, CMDX
is any Linux command.
Inspired from https://stackoverflow.com/a/2563551/6309601
Upvotes: 2
Reputation: 118605
alarm
won't help you here. The expression -CMD2flt="$(CMD3)"
on the command line expands the output of CMD3
to a variable before the perl script is launched.
Fortunately, it is easy to whip up your own timeout
script in perl.
#! perl
# timeout N cmd [arg1 [arg2 [...]]]
# execute cmd [arg1 [...]] and timeout after N seconds
$N = shift;
$pid = $$;
fork || exec($^X,"-e","sleep 1,kill(0,$pid) || exit for 1..$N;kill -9,$pid");
exec(@ARGV);
(The code inside the first exec
call is the poor man's alarm. It will monitor the calling process [with process id $pid
] for up to $N
seconds and then send a kill signal. It is more effective than Perl's alarm
, which may not be able to terminate all system calls or external commands).
Replace -CMD2flt=$(CMD3)
with -CMD2filt=$($HOME/bin/timeout 30 CMD3)
and you should be all set.
Upvotes: 4