ulimit -t 1 limits the script's CPU time to 1 second. When the script has consumed all its CPU time it gets killed.
To limit the CPU time of just one command in your script you can use parentheses to start it in a subshell with its own limit, e.g.
(ulimit -t 1; LD_PRELOAD=../../EasySandbox/EasySandbox.so ./a.out < $testin)
Answer from Florian Diesch on askubuntu.comhow to catch status code of killed process by bash script
sh - how do I watch for a process to have died in shell script? - Stack Overflow
unix - How to suppress Terminated message after killing in bash? - Stack Overflow
linux - Shell script process is getting killed automatically - Stack Overflow
I would do something like this:
#!/bin/bash
trap : SIGTERM SIGINT
echo $$
find / >/dev/null 2>&1 &
FIND_PID=$!
wait $FIND_PID
if [[ $? -gt 128 ]]
then
kill $FIND_PID
fi
Some explanation is in order, I guess. Out the gate, we need to change some of the default signal handling. : is a no-op command, since passing an empty string causes the shell to ignore the signal instead of doing something about it (the opposite of what we want to do).
Then, the find command is run in the background (from the script's perspective) and we call the wait builtin for it to finish. Since we gave a real command to trap above, when a signal is handled, wait will exit with a status greater than 128. If the process waited for completes, wait will return the exit status of that process.
Last, if the wait returns that error status, we want to kill the child process. Luckily we saved its PID. The advantage of this approach is that you can log some error message or otherwise identify that a signal caused the script to exit.
As others have mentioned, putting kill -- -$$ as your argument to trap is another option if you don't care about leaving any information around post-exit.
For trap to work the way you want, you do need to pair it up with wait - the bash man page says "If bash is waiting for a command to complete and receives a signal for which a trap has been set, the trap will not be executed until the command completes." wait is the way around this hiccup.
You can extend it to more child processes if you want, as well. I didn't really exhaustively test this one out, but it seems to work here.
$ ./test-k.sh &
[1] 12810
12810
$ kill 12810
$ ps -ef | grep find
$
Was looking for an elegant solution to this issue and found the following solution elsewhere.
trap 'kill -HUP 0' EXIT
My own man pages say nothing about what 0 means, but from digging around, it seems to mean the current process group. Since the script get's it's own process group, this ends up sending SIGHUP to all the script's children, foreground and background.
Edit: thank you guys, your comments were very helpful and help me to solve the problem, the code I used to solve the problem is at the end of the post (*), and for the executed command output "if we consider byeprogram produce some output to stdout" I think to redirect it to a pipe, but it did not work well
Hi every one, I am working on project, and I faced an a issue, the issue is that I cannot catch the exit code "status code" of process that worked in background, take this program as an example, that exits with 99 if it received a sigint, the code:
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
void bye(){
// exit with code 99 if sigint was received
exit(99);
}
int main(int argc,char** argv){
signal(SIGINT, bye);
while(1){
sleep(1);
}
return 0;
}then I compiled it using
`gcc example.c -o byeprogram`
in the same directory, I have my bash script:
set -x
__do_before_wait(){
##some commands
return 0
}
__do_after_trap(){
##some commands
return 0
}
runbg() {
local __start_time __finish_time __run_time
__start_time=$(date +%s.%N)
# Run the command in the background
($@) &
__pid=$!
trap '
kill -2 $__pid
echo $?
__finish_time=$(date +%s.%N)
__run_time=$(echo "$__finish_time - $__start_time" | bc -l)
echo "$__run_time"
__do_after_trap || exit 2
' SIGINT
__do_before_wait || exit 1
wait $__pid
## now if you press ctrl+c, it will execute the commands i wrote in trap
}
out=`runbg /path/to/byeprogram`my problem is I want to catch or print the code 99, but I cannot, I tried to execute the `byeprogram` from the terminal, and type ctrl+c, and it return 99, how to catch the 99 status code??
*solution:
runbg() {
# print status_code,run_time
# to get the status code use ( | gawk -F, {print $1})
# to get the run time use ( | gawk -F, {print $2})
__trap_code(){
kill -2 $__pid
wait $__pid
__status_code=$?
__finish_time=$(date +%s.%N)
__run_time=$(echo "$__finish_time - $__start_time" | bc -l)
echo "$__status_code,$__run_time"
__do_after_trap
exit 0
}
local __start_time __finish_time __run_time
__start_time=$(date +%s.%N)
($@) &
local __pid=$!
trap __trap_code SIGINT
__do_before_wait
wait $__pid
__status_code=$?
__finish_time=$(date +%s.%N)
__run_time=$(echo "$__finish_time - $__start_time" | bc -l)
echo "$__status_code,$__run_time"
}In order to silence the message, you must be redirecting stderr at the time the message is generated. Because the kill command sends a signal and doesn't wait for the target process to respond, redirecting stderr of the kill command does you no good. The bash builtin wait was made specifically for this purpose.
Here is very simple example that kills the most recent background command. (Learn more about $! here.)
kill $!
wait $! 2>/dev/null
Because both kill and wait accept multiple pids, you can also do batch kills. Here is an example that kills all background processes (of the current process/script of course).
kill $(jobs -rp)
wait $(jobs -rp) 2>/dev/null
I was led here from bash: silently kill background function process.
The short answer is that you can't. Bash always prints the status of foreground jobs. The monitoring flag only applies for background jobs, and only for interactive shells, not scripts.
see notify_of_job_status() in jobs.c.
As you say, you can redirect so standard error is pointing to /dev/null but then you miss any other error messages. You can make it temporary by doing the redirection in a subshell which runs the script. This leaves the original environment alone.
(script 2> /dev/null)
which will lose all error messages, but just from that script, not from anything else run in that shell.
You can save and restore standard error, by redirecting a new filedescriptor to point there:
exec 3>&2 # 3 is now a copy of 2
exec 2> /dev/null # 2 now points to /dev/null
script # run script with redirected stderr
exec 2>&3 # restore stderr to saved
exec 3>&- # close saved version
But I wouldn't recommend this -- the only upside from the first one is that it saves a sub-shell invocation, while being more complicated and, possibly even altering the behavior of the script, if the script alters file descriptors.
EDIT:
For more appropriate answer check answer given by Mark Edgar
Every process has to have a parent process (to collect exit status, at the very least). see man 2 wait. If a parent process dies, its children are sent a SIGHUP signal (see man 7 signal). SIGHUP is a catchable signal, but if the child doesn't catch it, the default action is to kill the child process.
See man nohup to keep things going.
To execute a background job and keep it running after terminal is closed use:
nohup command &>/dev/null &
Enable core dump in your system, it is the most commonly used method for app crash analysis. I know it is a bit painful to gdb core file, but more or less you can find something out of it. Here is a reference link for you.(http://www.cyberciti.biz/tips/linux-core-dumps.html).
Another way to do this is tracing you script by "strace -p PID-X", note that it will slow down your system, espeically several hours in your case, but it can be the last resort.
Hope above helpful to you.
Better to check all the signals generated and caught by OS at that time by specific script might be one of signal is causing to kill your process.
There really are only a couple of possibilities. Assuming you're just running this from the command line, you should see the message ... unless, of course, what you're doing puts the PID of your shell process in PIDS, in which case the kill would kill the (sub) shell running your command before you hit the echo.
Suggestion: echo $PIDS before you call kill and see what's there. In fact, I'd be tempted to comment out the kill and try the command, just to see what happens.
#!/bin/bash
PIDS=$(ps -e | grep $1 |grep -v grep| awk '{print $1}')
echo $PIDS
# kill -s SIGINT $PIDS
echo "Done sendings signal"
Of course, you can always run the script with bash -x to see everything.
Your script works. The only reason I can see for the echo not being executed is that some value of $1 and the script file name combine so that your script PID is also gathered, thereby making the script suicide.
The PIDS line spawns a process running ps, grep, another grep -- so you won't find in PIDS the processes running grep, but what about the parent process itself?
Try:
#!/bin/bash
PIDS=$(ps -e | grep $1 |grep -v grep | awk '{print $1}' | grep -v "^$$\$" )
kill -s SIGINT $PIDS
echo "Done sendings signal"
or run the pipes one after the other with suitable safety greps.
Edit: it is evident that the "$1" selection is selecting too much. So I'd rewrite the script like this:
#!/bin/bash
# Gather the output of "ps -e". This will also gather the PIDs of this
# process and of ps process and its subshell.
PSS=$( ps -e )
# Extract PIDs, excluding this one PID and excluding a process called "ps".
# Don't need to expunge 'grep' since no grep was running when getting PSS.
PIDS=$( echo "$PSS" | grep -v "\<ps\>" | grep "$1" | awk '{print $1}' | grep -v "^$$\$" )
if [ -n "$PIDS" ]; then
kill -s SIGINT $PIDS
else
echo "No process found matching $1"
fi
echo "Done sending signal."
With standard sh and bash, you can
set -e
It will
$ help set
...
-e Exit immediately if a command exits with a non-zero status.
It also works (from what I could gather) with zsh. It also should work for any Bourne shell descendant.
With csh/tcsh, you have to launch your script with #!/bin/csh -e
May be you could use:
$ <any_command> || exit 1
Your script is run on another shell and uses the -f option (follow) of tail which appends the output as the file grows. In short, the script has no exit point, so it's not supposed to end, even if you desire the script to do so.
tl;dr: create a bash exit hook and kill your background job from there.
Details:
Create a PID file in your
tail/grepscript like so:echo $$ > $HOME/script.pidAdd an exit hook to your login shell by adding something like this to your
$HOME/.bash_profile:function finish { # Your cleanup code here kill -9 `cat $HOME/script.pid` } trap finish EXITProfit.
This will break if you envoke your tail script multiple times. This could be handled by creating a lock file or skipping the script.pid file and crafting a killall <scriptname> inside the trap function.
Does the name of your script include MailSender? Try changing it, if so. Also, use pkill -9, it'll be cleaner:
#!/bin/bash
pkill -9 MailSender
echo starting
./MailSender
pkill will kill anything contained MailSender, maybe your script contain MailSender in its name. Change it.
Use a negative PID which will cause a process group to be killed. The -- tells kill that the rest of the arguments are not option switches so the hyphen (minus) before the PID won't confuse it.
kill -- -12345
Also, -9 is a last resort. Don't use it until you've tried at least -15 (SIGTERM, which is the default) first. This gives a program the chance to do housekeeping before it exits. See When should I use kill -9 or Useless use of kill -9 or kill -9.
killall might give you better results.
Warning: killall behaves differently on the different *nix's. On Linux, it will kill the processes with the titles matching the argument. On Solaris, it will kill EVERY process, not just the ones you specify. So on Solaris, running killall as root will effectively shut down the machine. Make sure you know which behavior the command follows