45

I am trying to detach a process from a bash script so that SIGINT will not be forwarded to the process when I exit the script.

I have used the disown command in terminal directly, however in bash, disown does not stop SIGINT from being forwarded. The purpose of this script is to start openocd and then gdb with a single invocation. Since the script never exits (it's running gdb) SIGINT is still forwarded from gdb to openocd which is a problem since SIGINT is used as the halt command in gdb.

In terminal it would look something like this:

$ openocd &    # run openocd demonized
$ disown $!    # disown last pid
$ gdb          # invoke GDB

when invoked on terminal in this order, the SIGINT is not passed from gdb to openocd. However if this same invocation was in a bash script, the SIGINT is passed.

Any help would be greatly appreciated.

ps this problem is in OS X but I am trying to use tools which are also portable to all Unix tools.

2
  • nohup isn't quite the right answer. You should add some pseudocode or example code to show more precisely what you want.
    – user732
    Commented Mar 15, 2016 at 0:38
  • 1
    Are you open to using a tool like screen? Commented Mar 15, 2016 at 2:52

6 Answers 6

38

To detach a process from a bash script:

nohup ./process &

If you stop your bash script with SIGINT (Ctrl+C), or the shell exits sending SIGHUP for instance, the process won't be bothered and will continue executing normally.  stdout and stderr will be redirected to a log file: nohup.out.

If you wish to execute a detached command while being able to see the output in the terminal, then use tail:

TEMP_LOG_FILE=tmp.log
> "$TEMP_LOG_FILE"
nohup ./process &> "$TEMP_LOG_FILE" & tail -f "$TEMP_LOG_FILE" &
2
  • Why is nohup necassary? What is the difference between nohup COMMAND & and COMMAND & if your goal is only to run command in background and free the terminal? Commented Feb 22, 2019 at 21:47
  • 1
    @JamesWierzba One among the differences is that if you need the command to continue to run even after exiting the shell, then nohup is the way to go. There are thousand of extensive explanations in the web. E.g. stackoverflow.com/questions/15595374/…
    – marc
    Commented Feb 23, 2019 at 0:03
34

For me this works perfectly fine with disown

command & disown
4
  • 2
    disown is the correct solution to use when you want to detach a process and be able to leave the shell without the process exiting. Very useful if you ssh in and want to run a job that takes longer than your ssh connection will survive (overnight, etc)
    – Ajax
    Commented Mar 9, 2021 at 0:24
  • Also, if you forget to run it immediately, just find the pid from ps -ef and just run disown 1234 w/ correct pid
    – Ajax
    Commented Mar 9, 2021 at 0:25
  • running command & disown on a terminal with ZSH works fine; no program exit on terminal clossing. But sourcing a file that contains a line with command & disown is able to remove job from jobs list, but exits program on terminal closing (If my tests are correct). I know there are some diferences between bash and zsh on several signal handling. I dont remember details. If that is your case use, nohup command & disown
    – manolius
    Commented Dec 3, 2021 at 17:11
  • This can fail when there are multiple jobs because disown (at least in Bash) targets the current job, which may not be the same as the last job started. A common scenario is that you edit a script with vim, put vim into the background with Ctrl+Z, and run the script with disown as described above—perfect, you have just disowned vim. I have been bitten by this disown-rienting behavior so many times… Commented Jul 13, 2023 at 13:17
6

The solution I found involves a program called 'detach' written by Annon Inglorion and downloadable from his website

Once compiled, it can be used in a script as follows:

$ ./detach -p debug.pid openocd <args> # detach openocd
$ gdb <args>                           # run gdb
$ kill -9 $(cat debug.pid)             # end openocd process
$ rm debug.pid                         # remove file containing process id

This first line creates a new process (running openocd) and stores the process id in file (debug.pid) for use later. This prevents the issues with grepping for the pid as provided in Oliver's answer. Upon exiting the next blocking program (gdb) the file storing the pid is used to kill the detached process directly.

2
  • 1
    Can confirm, detach makes wonders.
    – A S
    Commented Dec 23, 2019 at 6:47
  • 1
    Thanks! This is the only way that keeps my process running when the parent shell is killed. Crazy that this isn't possible with standard commands. Commented Oct 4, 2021 at 23:45
4

a simple and portable solution :

echo "openocd" | at now #openocd starts now, but via the at daemon, not the current shell!
pid=$(ps -ef | grep "[o]penocd" | awk '{print $1}')  
echo "openocd is running with pid: $pid"
gdb

Some portability caveats: ps options depends on the OS! you could instead use a variant of : { ps -ef || ps aux ;} | grep '[o]penocd | cut -f 1. at could not be available (weird, but this happens...). $(...) needs a not reallllly old shell, otherwise use backticks.

3
  • This seems dangerous, grepping for pid may do unexpected things if more than one process is running with the same name, or even, if another process contains the word openocd.
    – orion
    Commented Mar 15, 2016 at 8:06
  • 1
    @orion: i give a simple example to give the ideas, those concerns you mention are easy to get rid of : have at start a script that launches the program and gives out its pid instead in a file, and have the main script wait for that file to appear and then read the pid from it. Commented Mar 15, 2016 at 9:21
  • of course you should replace in my (overly simple) example the grep with a test inside awk, on the right column ($8, usually)(the columns depends on your os and version/options of ps) Commented Mar 15, 2016 at 10:42
3

Normal running of a process in the background, disown, nohup, etc is not going to work 100% because often child processes will still die on certain signals like SIGINT. What you need to do is use a different process group:

#!/bin/bash

(set -m; child_process &)

while [ true ]; do
   sleep 30
done

CTRL-C and the child will keep running unlike when using disown/nohup/whatever.

3
  • At which point in your code does the different process group come into play?
    – bomben
    Commented Jul 7, 2022 at 4:43
  • 1
    @bomben By creating a subshell (subshell) and set -m to enable job control within that subshell. The job control will force a new process group to be created when the child_process is run. Normally non-interactive shells don't have job control hence the set -m.
    – CR.
    Commented Jul 8, 2022 at 8:03
  • This should be the accepted answer. Neither nohup nor disown worked in general, only this subshell trick. Thanks
    – iluvatar
    Commented Feb 22 at 14:46
1

kstart5 from KDE, available in the package kde-cli-tools can help

kstart5 my-command &

We can as well manage multiple aspect of an x window if we are running a gui

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .