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.com
Discussions

how to catch status code of killed process by bash script
If you do a wait inside the trap, that will put the exit status (99) in $?. You can still also do the wait outside of the trap, but this one will return 130 (128+2) and not 99. Be aware that if you're calling runbg inside $(), it will run in a subshell. In this case the parent shell won't have the trap installed, and when you press Ctrl-c it will just exit normally. More on reddit.com
🌐 r/bash
8
4
January 17, 2025
sh - how do I watch for a process to have died in shell script? - Stack Overflow
I'm running a shell test program that I can view a progress bar but when I run it I keep getting a unary error . Is kill -0 a way to kill a subprocess in shell ? Or is there another method to tes... More on stackoverflow.com
🌐 stackoverflow.com
unix - How to suppress Terminated message after killing in bash? - Stack Overflow
How can you suppress the Terminated message that comes up after you kill a process in a bash script? I tried set +bm, but that doesn't work. I know another solution involves calling exec 2> /dev/ More on stackoverflow.com
🌐 stackoverflow.com
bash - Is there any way to tell if a shell script was killed with signal 9 - Unix & Linux Stack Exchange
I have a bash script (called from a java program) that keeps getting killed. I always catch the signal 15 with trap but then some other signal comes along that I suspect is signal 9 but am in basically blind as to if it is really signal 9. I know you can't trap signal 9, so is there any other way I can tell if signal 9 is killing my shell ... More on unix.stackexchange.com
🌐 unix.stackexchange.com
May 16, 2016
Top answer
1 of 6
15

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
$
2 of 6
9

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.

🌐
Reddit
reddit.com › r/bash › how to catch status code of killed process by bash script
r/bash on Reddit: how to catch status code of killed process by bash script
January 17, 2025 -

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"
}
🌐
Stack Overflow
stackoverflow.com › questions › 71578894 › how-do-i-watch-for-a-process-to-have-died-in-shell-script
sh - how do I watch for a process to have died in shell script? - Stack Overflow
To kill a process, one generally use the SIGQUIT/3 (quit program) or SIGKILL/9 (terminate program) ; the process could trap the signal and make a clean exit, or it could ignore the signal so the OS has to terminate it 'quick and dirty'.
Top answer
1 of 12
169

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.

2 of 12
21

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

Find elsewhere
Top answer
1 of 3
1

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.

2 of 3
0

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."
🌐
GitHub
github.com › facebookresearch › hyperreel › issues › 3
Bash script got killed suddenly · Issue #3 · facebookresearch/hyperreel
January 9, 2023 - Hi, Thanks for the code ! I am trying to run the experiment on the immersive dataset but the script got killed suddenly without any warnings or errors ! I have also properly adjust the data path in the local.yaml file like this: bash scr...
Author   facebookresearch
🌐
ErrorCrate
errorcrate.com › linux › killed
Killed - Linux Error | ErrorCrate
2 weeks ago - The 'Killed' error message is returned by the shell when a process is terminated by the kernel with a SIGKILL (Signal 9) signal. SIGKILL cannot be caught, blocked, or ignored by the application, resulting in an immediate exit. This most commonly happens because the kernel's Out-Of-Memory (OOM) ...
Top answer
1 of 4
83

Processes can call the _exit() system call (on Linux, see also exit_group()) with an integer argument to report an exit code to their parent. Though it's an integer, only the 8 least significant bits are available to the parent (exception to that is when using waitid() or handler on SIGCHLD in the parent to retrieve that code, though not on Linux).

The parent will typically do a wait() or waitpid() to get the status of their child as an integer (though waitid() with somewhat different semantics can be used as well).

On Linux and most Unices, if the process terminated normally, bits 8 to 15 of that status number will contain the exit code as passed to exit(). If not, then the 7 least significant bits (0 to 6) will contain the signal number and bit 7 will be set if a core was dumped.

perl's $? for instance contains that number as set by waitpid():

$ perl -e 'system q(kill $$); printf "%04x\n", $?'
000f # killed by signal 15
$ perl -e 'system q(kill -ILL $$); printf "%04x\n", $?'
0084 # killed by signal 4 and core dumped
$ perl -e 'system q(exit $((0xabc))); printf "%04x\n", $?'
bc00 # terminated normally, 0xbc the lowest 8 bits of the status

Bourne-like shells also make the exit status of the last run command in their own $? special parameter. However, it does not contain directly the number returned by waitpid(), but a transformation on it, and it's different between shells.

What's common between all shells is that $? contains the lowest 8 bits of the exit code (the number passed to exit()) if the process terminated normally.

Where it differs is when the process is terminated by a signal. In all cases, and that's required by POSIX, the number will be greater than 128. POSIX doesn't specify what the value may be. In practice though, in all Bourne-like shells that I know, the lowest 7 bits of $? will contain the signal number. But, where n is the signal number,

  • in ash, zsh, pdksh, bash, the Bourne shell, $? is 128 + n. What that means is that in those shells, if you get a $? of 129, you don't know whether it's because the process exited with exit(129) or whether it was killed by the signal 1 (HUP on most systems). But the rationale is that shells, when they do exit themselves, by default return the exit status of the last exited command. By making sure $? is never greater than 255, that allows to have a consistent exit status:

    $ bash -c 'sh -c "kill \$\$"; printf "%x\n" "$?"'
    bash: line 1: 16720 Terminated              sh -c "kill \$\$"
    8f # 128 + 15
    $ bash -c 'sh -c "kill \$\$"; exit'; printf '%x\n' "$?"
    bash: line 1: 16726 Terminated              sh -c "kill \$\$"
    8f # here that 0x8f is from a exit(143) done by bash. Though it's
       # not from a killed process, that does tell us that probably
       # something was killed by a SIGTERM
    
  • ksh93, $? is 256 + n. That means that from a value of $? you can differentiate between a killed and non-killed process. Newer versions of ksh, upon exit, if $? was greater than 255, kills itself with the same signal in order to be able to report the same exit status to its parent. While that sounds like a good idea, that means that ksh will generate an extra core dump (potentially overwriting the other one) if the process was killed by a core generating signal:

    $ ksh -c 'sh -c "kill \$\$"; printf "%x\n" "$?"'
    ksh: 16828: Terminated
    10f # 256 + 15
    $ ksh -c 'sh -c "kill -ILL \$\$"; exit'; printf '%x\n' "$?"
    ksh: 16816: Illegal instruction(coredump)
    Illegal instruction(coredump)
    104 # 256 + 15, ksh did indeed kill itself so as to report the same
        # exit status as sh. Older versions of `ksh93` would have returned
        # 4 instead.
    

    Where you could even say there's a bug is that ksh93 kills itself even if $? comes from a return 257 done by a function:

    $ ksh -c 'f() { return "$1"; }; f 257; exit'
    zsh: hangup     ksh -c 'f() { return "$1"; }; f 257; exit'
    # ksh kills itself with a SIGHUP so as to report a 257 exit status
    # to its parent
    
  • yash. yash offers a compromise. It returns 256 + 128 + n. That means we can also differentiate between a killed process and one that terminated properly. And upon exiting, it will report 128 + n without having to suicide itself and the side effects it can have.

    $ yash -c 'sh -c "kill \$\$"; printf "%x\n" "$?"'
    18f # 256 + 128 + 15
    $ yash -c 'sh -c "kill \$\$"; exit'; printf '%x\n' "$?"
    8f  # that's from a exit(143), yash was not killed
    

To get the signal from the value of $?, the portable way is to use kill -l:

$ /bin/kill 0
Terminated
$ kill -l "$?"
TERM

(for portability, you should never use signal numbers, only signal names)

On the non-Bourne fronts:

  • csh/tcsh and fish same as the Bourne shell except that the status is in $status instead of $? (note that zsh also sets $status for compatibility with csh (in addition to $?)).

  • rc: the exit status is in $status as well, but when killed by a signal, that variable contains the name of the signal (like sigterm or sigill+core if a core was generated) instead of a number, which is yet another proof of the good design of that shell.

  • es. the exit status is not a variable. If you care for it, you run the command as:

     status = <={cmd}
    

which will return a number or sigterm or sigsegv+core like in rc.

Maybe for completeness, we should mention zsh's $pipestatus and bash's $PIPESTATUS arrays that contain the exit status of the components of the last pipeline.

And also for completeness, when it comes to shell functions and sourced files, by default functions return with the exit status of the last command run, but can also set a return status explicitly with the return builtin. And we see some differences here:

  • bash and mksh (since R41, a regression^Wchange apparently introduced intentionally) will truncate the number (positive or negative) to 8 bits. So for instance return 1234 will set $? to 210, return -- -1 will set $? to 255.
  • zsh and pdksh (and derivatives other than mksh) allow any signed 32 bit decimal integer (-231 to 231-1) (and truncate the number to 32bits).
  • ash and yash allow any positive integer from 0 to 231-1 and return an error for any number out of that.
  • ksh93 for return 0 to return 320 set $? as is, but for anything else, truncate to 8 bits. Beware as already mentioned that returning a number between 256 and 320 could cause ksh to kill itself upon exit.
  • rc and es allow returning anything even lists.

Also note that some shells also use special values of $?/$status to report some error conditions that are not the exit status of a process, like 127 or 126 for command not found or not executable (or syntax error in a sourced file)...

2 of 4
41

When a process exits, it returns an integer value to the operating system. On most unix variants, this value is taken modulo 256: everything but the low-order bits is ignored. The status of a child process is returned to its parent through a 16-bit integer in which

  • bits 0–6 (the 7 low-order bits) are the signal number that was used to kill the process, or 0 if the process exited normally;
  • bit 7 is set if the process was killed by a signal and dumped core;
  • bits 8–15 are the process's exit code if the process exited normally, or 0 if the process was killed by a signal.

The status is returned by the wait system call or one of its siblings. POSIX does not specify the exact encoding of the exit status and signal number; it only provides

  • a way to tell whether the exit status corresponds to a signal or to a normal exit;
  • a way to access the exit code, if the process exited normally;
  • a way to access the signal number, if the process was killed by a signal.

Strictly speaking, there's no exit code when a process is killed by a signal: what there is instead is an exit status.

In a shell script, the exit status of a command is reported via the special variable $?. This variable encodes the exit status in an ambiguous way:

  • If the process exited normally then $? is its exit status.
  • If the process was killed by a signal then $? is 128 plus the signal number on most systems. POSIX only mandates that $? is greater than 128 in this case; ksh93 adds 256 instead of 128. I've never seen a unix variant that did anything other than add a constant to the signal number.

Thus in a shell script you cannot tell conclusively whether a command was killed by a signal or exited with a status code greater than 128, except with ksh93. It is very rare for programs to exit with status codes greater than 128, in part because programmers avoid it due to the $? ambiguity.

SIGINT is signal 2 on most unix variants, thus $? is 128+2=130 for a process that was killed by SIGINT. You'll see 129 for SIGHUP, 137 for SIGKILL, etc.

🌐
PerlMonks
perlmonks.org
Why does my script exit with "Killed" - that's all...
isync has asked for the wisdom of the Perl Monks concerning the following question: · www.com | www.net | www.org