linux kill process using timeout in milliseconds
You can do something like this:
#!/bin/bash
#execute command in background
<command> &
#get process ID
PROC=$!
#sleep for 10 milliseconds then kill command
(usleep 10000; kill $PROC) &
#bring back the process ID, finish command or kill it
fg $PROC
Preventing Terminated message when killing subprocess
To avoid the message you can disown the process
(./tools/usleep $TIMEOUT ; kill $PROC &> /dev/null) &
disown %
and then you cannot wait on it, or you can put it in a subshell:
( (./tools/usleep $TIMEOUT ; kill $PROC &> /dev/null) & )
but of course then you cannot kill it as $! wont be right.
My fedora 21 timeout takes floating point durations:
$ time timeout .1 sleep 1
real 0m0.103s
user 0m0.002s
sys 0m0.002s
Timeout a command in bash without unnecessary delay
I think this is precisely what you are asking for:
http://www.bashcookbook.com/bashinfo/source/bash-4.0/examples/scripts/timeout3
#!/bin/bash
#
# The Bash shell script executes a command with a time-out.
# Upon time-out expiration SIGTERM (15) is sent to the process. If the signal
# is blocked, then the subsequent SIGKILL (9) terminates it.
#
# Based on the Bash documentation example.
# Hello Chet,
# please find attached a "little easier" :-) to comprehend
# time-out example. If you find it suitable, feel free to include
# anywhere: the very same logic as in the original examples/scripts, a
# little more transparent implementation to my taste.
#
# Dmitry V Golovashkin <Dmitry.Golovashkin@sas.com>
scriptName="${0##*/}"
declare -i DEFAULT_TIMEOUT=9
declare -i DEFAULT_INTERVAL=1
declare -i DEFAULT_DELAY=1
# Timeout.
declare -i timeout=DEFAULT_TIMEOUT
# Interval between checks if the process is still alive.
declare -i interval=DEFAULT_INTERVAL
# Delay between posting the SIGTERM signal and destroying the process by SIGKILL.
declare -i delay=DEFAULT_DELAY
function printUsage() {
cat <<EOF
Synopsis
$scriptName [-t timeout] [-i interval] [-d delay] command
Execute a command with a time-out.
Upon time-out expiration SIGTERM (15) is sent to the process. If SIGTERM
signal is blocked, then the subsequent SIGKILL (9) terminates it.
-t timeout
Number of seconds to wait for command completion.
Default value: $DEFAULT_TIMEOUT seconds.
-i interval
Interval between checks if the process is still alive.
Positive integer, default value: $DEFAULT_INTERVAL seconds.
-d delay
Delay between posting the SIGTERM signal and destroying the
process by SIGKILL. Default value: $DEFAULT_DELAY seconds.
As of today, Bash does not support floating point arithmetic (sleep does),
therefore all delay/time values must be integers.
EOF
}
# Options.
while getopts ":t:i:d:" option; do
case "$option" in
t) timeout=$OPTARG ;;
i) interval=$OPTARG ;;
d) delay=$OPTARG ;;
*) printUsage; exit 1 ;;
esac
done
shift $((OPTIND - 1))
# $# should be at least 1 (the command to execute), however it may be strictly
# greater than 1 if the command itself has options.
if (($# == 0 || interval <= 0)); then
printUsage
exit 1
fi
# kill -0 pid Exit code indicates if a signal may be sent to $pid process.
(
((t = timeout))
while ((t > 0)); do
sleep $interval
kill -0 $$ || exit 0
((t -= interval))
done
# Be nice, post SIGTERM first.
# The 'exit 0' below will be executed if any preceeding command fails.
kill -s SIGTERM $$ && kill -0 $$ || exit 0
sleep $delay
kill -s SIGKILL $$
) 2> /dev/null &
exec "$@"
Bash: wait with timeout
Write the PIDs to files and start the apps like this:
pidFile=...
( app ; rm $pidFile ; ) &
pid=$!
echo $pid > $pidFile
( sleep 60 ; if [[ -e $pidFile ]]; then killChildrenOf $pid ; fi ; ) &
killerPid=$!
wait $pid
kill $killerPid
That would create another process that sleeps for the timeout and kills the process if it hasn't completed so far.
If the process completes faster, the PID file is deleted and the killer process is terminated.
killChildrenOf
is a script that fetches all processes and kills all children of a certain PID. See the answers of this question for different ways to implement this functionality: Best way to kill all child processes
If you want to step outside of BASH, you could write PIDs and timeouts into a directory and watch that directory. Every minute or so, read the entries and check which processes are still around and whether they have timed out.
EDIT If you want to know whether the process has died successfully, you can use kill -0 $pid
EDIT2 Or you can try process groups. kevinarpe said: To get PGID for a PID(146322):
ps -fjww -p 146322 | tail -n 1 | awk '{ print $4 }'
In my case: 145974. Then PGID can be used with a special option of kill to terminate all processes in a group: kill -- -145974
Un*x shell script: what is the correct way to run a script for at most x milliseconds?
Have a look at this script: http://www.pixelbeat.org/scripts/timeout
Note timeouts of less that one second are pretty much nonsensical on most systems due to scheduling delays etc. Note also that newer coreutils has the timeout command included and it has a resolution of 1 second.
How to keep running a program during a time period?
If you want to use timeout:
timeout 5s ./a.out
You can write a short script and easily set an end time
with date -d "date string" +%s
to get a future time in seconds. Then just compare current time
to end time
and break on true
. This allows you to capture additional data during your execution time period. For example, the following code sets the end time 5 seconds
in the future and then loops until current time
equals end
.
#!/bin/bash
end=$(date -d "+ 5 seconds" +%s) # set end time with "+ 5 seconds"
declare -i count=0
while [ $(date +%s) -lt $end ]; do # compare current time to end until true
((count++))
printf "working... %s\n" "$count" # do stuff
sleep .5
done
output:
$ bash timeexec.sh
working... 1
working... 2
working... 3
working... 4
working... 5
working... 6
working... 7
working... 8
working... 9
In your case you would do something like
./a.out & # start your application in background
apid=$(pidof a.out) # save PID of a.out
while [ $(date +%s) -lt $end ]; do
# do stuff, count, etc.
sleep .5 # something to prevent continual looping
done
kill $apid # kill process after time test true
Using module 'subprocess' with timeout
In Python 3.3+:
from subprocess import STDOUT, check_output
output = check_output(cmd, stderr=STDOUT, timeout=seconds)
output
is a byte string that contains command's merged stdout, stderr data.
check_output
raises CalledProcessError
on non-zero exit status as specified in the question's text unlike proc.communicate()
method.
I've removed shell=True
because it is often used unnecessarily. You can always add it back if cmd
indeed requires it. If you add shell=True
i.e., if the child process spawns its own descendants; check_output()
can return much later than the timeout indicates, see Subprocess timeout failure.
The timeout feature is available on Python 2.x via the subprocess32
backport of the 3.2+ subprocess module.
WaitForExitAsync with a timeout
You need to use CancellationTokenSource
. It has a ctor which accepts a TimeSpan
var timeoutSignal = new CancellationTokenSource(TimeSpan.FromSeconds(3));
try
{
await CMD.WaitForExitAsync(timeoutSignal.Token);
} catch (OperationCanceledException)
{
CMD.Kill();
}
When the CTS signals then the awaited operation will throw an OperationCanceledException
. So you need to wrap your await
call into a try
-catch
to handle cancelled operation properly.
UPDATE #1: Capture STDOUT with async wait of exit
Naive approach
First let me share with you the naive version of the code
Console.WriteLine("Launch ping with fifteen retries");
var terminal = Process.Start(new ProcessStartInfo("/sbin/ping")
{
RedirectStandardOutput = true,
Arguments = "-c 15 stackoverflow.com",
UseShellExecute = false,
});
_ = Task.Run(() =>
{
string line = null;
while ((line = terminal.StandardOutput.ReadLine()) != null)
Console.WriteLine(line);
});
var timeoutSignal = new CancellationTokenSource(TimeSpan.FromSeconds(3));
try
{
await terminal.WaitForExitAsync(timeoutSignal.Token);
Console.WriteLine("Ping has been Finished");
}
catch (OperationCanceledException)
{
terminal.Kill();
Console.WriteLine("Ping has been Terminated");
}
- I'm using .NET on a Macintosh machine so, I don't have
ping.exe
rather than I can run/sbin/ping
command - I ping stackoverflow fifteen times to make sure the command runs more than 3 seconds
- I've moved the
StandardOutput
reading to a separate thread (Task.Run
)- Without that, the cancellation signal will not have any effect
- The rest of the code same as above + debug logging
Suggested approach
The Process
class does expose a capability to read data asynchronously from the StandardOutput
without the need to do extra tricks
Console.WriteLine("Launch ping with fifteen retries");
var terminal = new Process()
{
StartInfo = new ProcessStartInfo("/sbin/ping")
{
RedirectStandardOutput = true,
Arguments = "-c 15 stackoverflow.com",
UseShellExecute = false,
}
};
terminal.OutputDataReceived += (s, e) => Console.WriteLine(e.Data);
terminal.Start();
terminal.BeginOutputReadLine();
var timeoutSignal = new CancellationTokenSource(TimeSpan.FromSeconds(3));
try
{
await terminal.WaitForExitAsync(timeoutSignal.Token);
Console.WriteLine("Ping has been Finished");
}
catch (OperationCanceledException)
{
terminal.Kill();
Console.WriteLine("Ping has been Terminated");
}
Let me highlight only the differences
- Rather than starting the process right away, first we create a Process and specify its
StartInfo
property - Then we subscribe to the
OutputDataReceived
event- Its EventArgs'
Data
property contains the newly available information
- Its EventArgs'
- After the subscription we can call the
Start
method - And finally we need to call the
BeginOutputReadLine
method to tell the Process fire the above event handler whenever new data is available on the standard output
Related Topics
How to Check If Emacs in Frame or in Terminal
Can't Load Mod_Wsgi Compiled for Python 3
Can't Untar a Complete Directory Using Tar -Cvpzf
Relative-To-Executable Path to Ld-Linux Dynamic Linker/Interpreter
How to Run a Linux Executable from Any Directory in Terminal
How to Automatically Close The Execution of The 'Qemu' After End of Process
How to See Output to Stdout After Disown and Logout
Arduino Upload Error "Stk500_Recv(): Programmer Is Not Responding" in Fedora
Can't Hard Link The Gitconfig File
Run Script on Startup with Raspbian Jessi Wheezy and Raspberry Pi2B
Shell: What Is The Purpose of ${Var:-} When Var Is Unset or Null
How to Get a Linux Coredump That Only Contains Callstack, Threads, and Local Variables
Succinct Way to Print All Lines Up Until The Last Line That Matches a Given Pattern
Passwd in One Command Isn't Working
How to Use Multiple Threads for Zlib Compression (Same Input Source)