In a Linux shell script I would like to use the timeout command to end another command if some time limit is reached. In general:
timeout -s SIGTERM 100 command
But I also want that my shell script exits when the command is failing for some reason. If the command is failing early enough, the time limit will not be reached, and timeout will exit with exit code 0. Thus the error cannot be trapped with trap or set -e, as least I have tried it and it did not work. How can I achieve what I want to do?
Your situation isn't very clear because you haven't included your code in the post.
timeout does exit with the exit code of the command if it finishes before the timeout value.
For example:
timeout 5 ls -l non_existent_file
# outputs ERROR: ls: cannot access non_existent_file: No such file or directory
echo $?
# outputs 2 (which is the exit code of ls)
From man timeout:
If the command times out, and --preserve-status is not set, then
exit with status 124. Otherwise, exit with the status of COMMAND. If
no signal is specified, send the TERM signal upon timeout. The TERM
signal kills any process that does not block or catch that signal.
It may be necessary to use the KILL (9) signal, since this signal
cannot be caught, in which case the exit status is 128+9 rather than
124.
See BashFAQ105 to understand the pitfalls of set -e.
Related
I have a bash script, in which I call another script and sometimes second script hangs. Is there any way to check if it is hung or not. And I can't make any changes is the second script.
#!/bin/bash
calling second script(thata might hang)
if hang then do something
If you already know a threshold time, that after that script is considered hung. you can use timeout.
timeout 30 bash script.sh
command bash script.sh will run until it finish in less that 30 seconds or gets killed by timeout. You can adjust the time according to your environment.
Command Reference:
timeout
Usage: timeout [OPTION] DURATION COMMAND [ARG]...
or: timeout [OPTION]
Start COMMAND, and kill it if still running after DURATION.
Please refer to respective man page for options.
When you want to set a time limit for a process, you can simply use timeout before the process:
timeout 1.5s COMMAND
This will kill the COMMAND if it was not done after 1.5 seconds.
I used that command in some bash scripts; How can i know if one process was completely done before the time limit, or it was killed (because of exceeding the time limit)?
The Gnu timeout command normally returns a status code of 124 if the timeout was exceeded. Otherwise, it returns the status code returned by the command itself. So you can test the status code by grabbing the value of $? immediately after executing timeout:
timeout 1.5s COMMAND
status=$?
if ((status==124)); then
# command timed out
elif (status!=0)); then
# command terminated in time, but it returned an error status
else
# command terminated in time and reported success
fi
If your command might return the status code 124, then you would have to use the --preserve-status option and check to see if the command was terminated by the signal you tell timeout to send. See the man timeout for details.
Add && echo >> time_limit.txt after COMMAND:
timeout 1.5s COMMAND && echo >> time_limit.txt
So, if you want to see if the COMMAND was killed, check the existence of file time_limit.txt. If that file exists, it means the command was NOT killed. Otherwise, the command was killed.
In bash script, you can check the existence of that file as follow:
if [[ -r time_limit.txt ]]then;
{
echo "The command was NOT killed"
}
else
{
echo "The command was killed"
}
I have a bash script that mounts and unmounts a device, which performing some read operations in between. Since the device is very slow, the script takes about 15 seconds to complete (the mount taking atleast 5-6 seconds). Since leaving this device mounted can cause other problems, I don't want this script to be interrupted.
Having said that, I can correctly handle SIGINT (Ctrl+c), but when I try to handle SIGTSTP (Ctrl+z), the script freezes. Which means the signal is trapped but the handler doesn't run.
#!/bin/sh
cleanup()
{
# Don't worry about unmounting yet. Just checking if trap works.
echo "Quitting..." > /dev/tty
exit 0
}
trap 'cleanup' SIGTSTP
...
I manually have to send the KILL signal to the process. Any idea why this is happening and how I can fix it?
The shell does not execute the trap until the currently executing process terminates. (at least, that is the behavior of bash 3.00.15). If you send SIGINT via ^c, it is sent to all processes in the foreground process group; if the program currently executing receives it and terminates then bash can execute the trap. Similarly with SIGTSTP via ^z; bash receives the signal but does not execute the trap until the program that was being run terminates, which it does not do if it takes the default behavior and is suspended. Try replacing ... with a simple read f and note that the trap executes immediately.
I'm writing a script and at some point I call to "command1" which
does not stop until it CTRL+C is invoked.
Is there a way to state a timeout for a command? Like:
command1 arguments -timeout 10
How do I write a CTRL+C command in textual form?
Thx!
You can use the timeout command from GNU coreutils (you may need to install it first, but it comes in most, if not all, Linux distributions):
timeout [OPTION] DURATION COMMAND [ARG]...
For instance:
timeout 5 ./test.sh
will terminate the script after 5 seconds of execution. If you want to send a KILL signal (instead of TERM), use -kflag.
Here you have the full description of the timeout command.
I just tried
jekyll -server & sleep 10;pkill jekyll
Could do for your situation.
in your script you can set a wait. wait 10 would wait 10 seconds and as for exiting the program without CTRL + C look into the exit command. If you use exit 0 it means ok. There are different versions, but I don't know what they mean exactly off the top of my head.
exit 1
exit 2..... so on and so forth
Update
# Celada
No need to bash. You could have just said "maybe you didn't understand the question correctly" Stackoverflow is here to help people learn, not tear them down. They invented Reddit for that. As for the exit codes, you can force the program to exit by issuing the exit() command with a code. Directly from linux.die.net.
Exit Code Number Meaning Example Comments
1 Catchall for general errors let "var1 = 1/0" Miscellaneous errors, such as "divide by zero"
2 Misuse of shell builtins (according to Bash documentation) Seldom seen, usually defaults to exit code 1
126 Command invoked cannot execute Permission problem or command is not an executable
127 "command not found" Possible problem with $PATH or a typo
128 Invalid argument to exit exit 3.14159 exit takes only integer args in the range 0 - 255 (see footnote)
128+n Fatal error signal "n" kill -9 $PPID of script $? returns 137 (128 + 9)
130 Script terminated by Control-C Control-C is fatal error signal 2, (130 = 128 + 2, see above)
255* Exit status out of range exit -1 exit takes only integer args in the range 0 - 255
If I send a SIGTERM signal to a process using the kill command, I expect an exit code, but I always get 0 (zero) when running the below command after killing a process:
echo $?
According to the answer in this post, I should get 143 when sending a SIGTERM to a process: Always app Java end with "Exit 143" Ubuntu
But I donĀ“t get that exit code. Why?
The exit code you get is for the kill command itself. 0 means it succeeded, i.e. the other process got the signal you sent it. kill just doesn't report the exit status for the process, since it can't even be sure the other process exited as a result of the signal it sent.