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
🌐
Stack Overflow
stackoverflow.com › questions › 24530524 › bash-script-gets-killed-by-system
python - Bash script gets killed by system - Stack Overflow
It seems udev is killing my bash script, but not the python script. Therefore I have to detach the process somehow.
🌐
Spiceworks
community.spiceworks.com › software & applications
Shell commands are getting killed - Software & Applications - Spiceworks Community
May 8, 2011 - Hi, We have realy strange phenomenon on our aix 5.3.12 box. We have a ksh script containing simple commands like ‘ls’, ‘mv’ etc. realy nothing complicated. When this script is runing in the background, sometimes (not always) some command are mysteriously getting killed, what we get in the log file is a message like: test.sh [20]: 123456 Killed (where line 20 is: ‘ls abc.txt’) When in the foreground it’s never happend.
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.

Top answer
1 of 2
6

The process your cmd is supposed to be run in will be killed by the SIGHUP signal between the fork() and the exec(), and any nohup wrapper or other stuff will have no chance to run and have any effect. (You can check that with strace)

Instead of nohup, you should set SIGHUP to SIG_IGN (ignore) in the parent shell before executing your background command; if a signal handler is set to "ignore" or "default", that disposition will be inherited through fork() and exec(). Example:

#! /bin/sh
trap '' HUP    # ignore SIGHUP
xclock &
trap - HUP     # back to default

Or:

#! /bin/sh
(trap '' HUP; xclock &)

If you run this script with xfce4-terminal -H -x script.sh, the background command (xclock &) will not be killed by the SIGHUP sent when script.sh terminates.

When a session leader (a process that "owns" the controlling terminal, script.sh in your case) terminates, the kernel will send a SIGHUP to all processes from its foreground process group; but set -m will enable job control and commands started with & will be put in a background process group, and they won't signaled by SIGHUP.

If job control is not enabled (the default for a non-interactive script), commands started with & will be run in the same foreground process group, and the "background" mode will be faked by redirecting their input from /dev/null and letting them ignore SIGINT and SIGQUIT.

Processes started this way from a script which once run as a foreground job but which has already exited won't be signaled with SIGHUP either, since their process group (inherited from their dead parent) is no longer the foreground one on the terminal.

Extra notes:

The "hold mode" seems to be different between xterm and xfce4-terminal (and probably other vte-based terminals). While the former will keep the master side of the pty open, the latter will tear it off after the program run with -e or -x has exited, causing any write to the slave side to fail with EIO. xterm will also ignore WM_DELETE_WINDOW messages (ie it won't close) while there are still processes from the foreground process group running.

2 of 2
0

I have been playing with this. I can't figure it out, but here is what I have discovered. I used sleep 3 as my cmd.

These two work. I have no idea what the ls at the end does. The brackets and double nohup, well they make a sub-process (I think that is how nohup works). I have no idea why nohup on its own does not work.

#!/bin/bash

nohup nohup sleep 3 &
ls #no idea why I need this

and

#!/bin/bash

(
nohup sleep 3 &
ls #no idea why I need this
)

/bin/true works in place of ls. Seems like we need to call an external command. Still no idea why.

Find elsewhere
🌐
GitHub
github.com › facebookresearch › hyperreel › issues › 3
Bash script got killed suddenly · Issue #3 · facebookresearch/hyperreel
January 9, 2023 - scripts/run_one_immersive.sh: line 19: 14469 Killed CUDA_VISIBLE_DEVICES=$1 python main.py experiment/dataset=immersive experiment/training=immersive_tensorf experiment.training.val_every=5 experiment.training.test_every=10 experiment.training.ckpt_every=10 experiment.training.render_every=30 experiment.training.num_epochs=30 experiment/model=immersive_sphere experiment.params.print_loss=True experiment.dataset.collection=$2 +experiment/regularizers/tensorf=tv_4000 experiment.dataset.start_frame=$3 experiment.params.name=immersive_$2_start_$3
Author   facebookresearch
Top answer
1 of 3
5

A few things that may cause a shell to exit (not exhaustive):

  • calling the exit utility. Let's not forget about the obvious
  • calling the return utility. In the case of bash that will return only if in a function or sourced file.
  • exec cmd. That will execute cmd in the same process so in effect breaking out of that loop. The script will end when cmd exits.
  • set -e/set -o errexit is enabled (see also the SHELLOPTS environment variable for bash) and a command exits with an error.
  • set -u/set -o nounset is enabled and an unset variable is referenced.
  • a DEBUG or ERR trap is defined that calls exit.
  • Failing special builtins. Failure of special builtins (like set, :, eval...) causes the shell to exit. In the case of bash though, that only happens in POSIX mode (like when POSIXLY_CORRECT is in the environment or when invoked as sh...) and even then not for all special builtins. For instance : > / will cause the shell to exit.
  • as mentioned by @schily, syntax error (like in code that is only reached conditionally).
  • division by 0 (in $((1/x)) or ${array[1/x]}).
  • internal bash error for instance because some limit is reached:
    • fails to allocate memory
    • fails to fork a process
    • stack size exceeded (for instance when using function recursion)
    • Some other limits in place via ulimit (which may also cause some signals to be sent).
  • killed by a another process. Another process can call kill() to explicitly kill the interpreter of your script.
  • killed by the system.
    • SIGINT/SIGQUIT. If you press ^C/^\.
    • SIGHUP. If the terminal is disconnected.
    • SIGSEGV/SIGBUS/SIGILL. The bash command does something wrong (a bug) or failing hardware (memory).
    • SIGPIPE: builtin (echo, printf) writing to a now-closed pipe or socket (could also happen for error messages if stderr is a pipe).

The first thing to check would be the error messages and the exit status.

2 of 3
0

A syntax error in a script will terminate the script.

If your script code includes shell variables that may include spaces in some cases, this may cause a syntax error in case the shell variable is not enclosed in double quotes.

🌐
Unix.com
unix.com › shell-programming-and-scripting › 122946-command-use-if-someone-killed-script-between.html
command to use if someone killed the script in between?
I am trying to kill a shell script by grepping it, but the machine is being shutdown totally when i kill it Below is the code kill `ps -ef |grep test.sh| grep -v grep` stat=$? if # check the return code then echo " script killed at $(date +%D@%T) " else echo " script... (5 Replies) ... I have a script that calls another script within it that takes about 1 hour to execute. I am noticing that the parent script that calls the child script is getting killed.
Top answer
1 of 2
5

A process isn't "killed with SIGHUP" -- at least, not in the strict sense of the word. Rather, when the connection is dropped, the terminal's controlling process (in this case, Bash) is sent a hang-up signal*, which is commonly abbreviated the "HUP signal", or just SIGHUP.

Now, when a process receives a signal, it can handle it any way it wants**. The default for most signals (including HUP) is to exit immediately. However, the program is free to ignore the signal instead, or even to run some kind of signal handler function.

Bash chooses the last option. Its HUP signal handler checks to see if the "huponexit" option is true, and if so, sends SIGHUP to each of its child processes. Only once its finished with that does Bash exit.

Likewise, each child process is free to do whatever it wants when it receives the signal: leave it set to the default (i.e. die immediately), ignore it, or run a signal handler.

Nohup only changes the default action for the child process to "ignore". Once the child process is running, however, it's free change its own response to the signal.

This, I think, is why some programs die even though you ran them with nohup:

  1. Nohup sets the default action to "ignore".
  2. The program needs to do some kind of cleanup when it exits, so it installs a SIGHUP handler, incidentally overwriting the "ignore" flag.
  3. When the SIGHUP arrives, the handler runs, cleaning up the program's data files (or whatever needed to be done) and exits the program.
  4. The user doesn't know or care about the handler or cleanup, and just sees that the program exited despite nohup.

This is where "disown" comes in. A process that's been disowned by Bash is never sent the HUP signal, regardless of the huponexit option. So even if the program sets up its own signal handler, the signal is never actually sent, so the handler never runs. Note, however, that if the program tries to display some text to a user that's logged out, it will cause an I/O error, which could cause the program to exit anyway.

* And, yes, before you ask, the "hang-up" terminology is left over from UNIX's dialup mainframe days.

** Most signals, anyway. SIGKILL, for instance, always causes the program to terminate immediately, period.

2 of 2
3

Points 1-4 are correct. I know nothing about point 5. As for your final point, a fine application, screen, will allow you to let all processes run to their natural end, regardless of how you terminate your connection. Screen is in the repos.

The man description of screen is not easy to read, but, among other things, it states:

When screen is called, it creates a single window with a shell in it (or the specified command) and then gets out of your way so that you can use the program as you normally would. Then, at any time, you can create new (full-screen) windows with other programs in them (including more shells), kill existing windows, view a list of windows, turn output logging on and off, copy-and-paste text between windows, view the scrollback history, switch between windows in whatever manner you wish, etc. All windows run their programs completely independent of each other. Programs continue to run when their window is currently not visible and even when the whole screen session is detached from the user's terminal.

When a program terminates, screen (per default) kills the window that contained it. If this window was in the foreground, the display switches to the previous window; if none are left, screen exits.

I have highlighted the most important part: you can detach the window with the command Ctrl+a+d, and then you may kill/logout your session, and the now-detached window will continue to live, with the programs inside still running. When you connect back, for instance by initiating a new ssh session, the command screen -r will resume the screen session which had been detached earlier, with all output to standard error/output clearly visible.

🌐
Unix Community
community.unix.com › shell programming and scripting
Killing a shell script - Shell Programming and Scripting - Unix Linux Community
August 26, 2009 - Hi, If I have a large shell script running as root, say for example like one that copies a ton of files, how would I kill the shell script and any processes that it created? Thanks