Why is nohup required and disown doesn't work by itself? - bash

Consider this snippet as being saved in a file called snippet.sh:
nohup xmessage HI </dev/null &>/dev/null & disown
sleep 3
From the same directory, do xterm -e bash snippet.sh.
After 3 seconds, the xterm should disappear while the xmessage window lingers. All good and well. But what if the nohup is removed from the command in the snippet file? Then the xmessage which disappears along with the xterm. The bash documentation seems to indicate that disown should, by itself, be sufficient to prevent SIGHUP from being sent:
The shell exits by default upon receipt of a SIGHUP. Before exiting, an interactive shell resends
the SIGHUP to all jobs, running or stopped. Stopped jobs are sent SIGCONT to ensure that they
receive the SIGHUP. To prevent the shell from sending the signal to a particular job, it should be
removed from the jobs table with the disown builtin (see SHELL BUILTIN COMMANDS below) or marked to
not receive SIGHUP using disown -h.
So, the question is, why won't the xmessage window linger without nohup?

disown is sufficient to prevent the shell from sending the signal, but it doesn't stop anyone else.
In particular, the shell is the controlling process of the terminal with xmessage in its process group, and POSIX says that on exit:
If the process is a controlling process, the SIGHUP signal shall be sent to each process in the foreground process group of the controlling terminal belonging to the calling process.

Related

do not send hangup signal to background process when bash exit

I know when shell exits or itself receives SIGHUP, it will send SIGHUP to all background process.
'nohup cmd' or 'disown' will tell bash not to send SIGHUP. Is there a shell setting so that bash will always not send SIGHUP?
I want my backgroup process to run when bash got killed accidentally for various reasons.
Thanks.
Sounds like you might want to look into jobs and disown. https://www.gnu.org/software/bash/manual/html_node/Signals.html

How child processes gets terminated when the parent is killed using SIGINT?

#!/usr/bin/env bash
for i in $(seq 1 $1);
do
./extended&
done
wait
This is my bash script and I execute the extended binary as many times as specified in command line argument. When I kill the bash script using SIGINT the child processes also killed. I've called wait in the bash script I couldn't figure how the child processes are killed. I know that wait will make the parent to wait till child terminates.
bash sends a SIGHUP (hang-up signal) to all children on exit by default. If you don't want this behaviour use disown -h
From man bash:
To prevent the shell from sending the signal to a particular job, it should be removed from the jobs table with the disown builtin or marked to not receive SIGHUP
using disown -h.

Exit zsh, but leave running jobs open?

Just switched from bash to zsh.
In bash, background tasks continue running when the shell exits. For example here, dolphin continues running after the exit:
$ dolphin .
^Z
[1]+ Stopped dolphin .
$ bg
[1]+ dolphin . &
$ exit
This is what I want as the default behavior.
In contrast, zsh's behavior is to warn about running jobs on exit, then close them if you exit again. For example here, dolphin is closed when the second exit-command actually exits the shell:
% dolphin .
^Z
zsh: suspended dolphin .
% bg
[1] + continued dolphin .
% exit
zsh: you have running jobs.
% exit
How do I make zsh's default behavior here like bash's?
Start the program with &!:
dolphin &!
The &! (or equivalently, &|) is a zsh-specific shortcut to both background and disown the process, such that exiting the shell will leave it running.
From the zsh documentation:
HUP
... In zsh, if you have a background job running when the shell exits, the shell will assume you want that to be killed; in this case it is sent a particular signal called SIGHUP... If you often start jobs that should go on even when the shell has exited, then you can set the option NO_HUP, and background jobs will be left alone.
So just set the NO_HUP option:
% setopt NO_HUP
I have found that using a combination of nohup, &, and disown works for me, as I don't want to permanently cause jobs to run when the shell has exited.
nohup <command> & disown
While just & has worked for me in bash, I found when using only nohup, &, or disown on running commands, like a script that calls a java run command, the process would still stop when the shell is exited.
nohup makes the command ignore NOHUP and SIGHUP signals from the shell
& makes the process run in the background in a subterminal
disown followed by an argument (the index of the job number in your jobs list) prevents the shell from sending a SIGHUP signal to child processes. Using disown without an argument causes it to default to the most recent job.
I found the nohup and disown information at this page, and the & information in this SO answer.
Update
When I originally wrote this, I was using it for data processing scripts/programs. For those kinds of use cases, something like ts (task-spooler), works nicely.
I typically use screen for keeping background jobs running.
1) Create a screen session:
screen -S myScreenName
2) Launch your scripts,services,daemons or whatever
3) Exit (detach) screen-session with
screen -d
or
shortcut ALT+A then d
After few hundreds of years - if you want to resume your session (reattach):
screen -r myScreenName
If you want to know if there's a screen-session, its name and its status (attached or detached):
screen -ls
This solution works on all terminal interpreters like bash, zsh etc.
See also man screen

Multiple process from one bash script [duplicate]

I'm trying to use a shell script to start a command. I don't care if/when/how/why it finishes. I want the process to start and run, but I want to be able to get back to my shell immediately...
You can just run the script in the background:
$ myscript &
Note that this is different from putting the & inside your script, which probably won't do what you want.
Everyone just forgot disown. So here is a summary:
& puts the job in the background.
Makes it block on attempting to read input, and
Makes the shell not wait for its completion.
disown removes the process from the shell's job control, but it still leaves it connected to the terminal.
One of the results is that the shell won't send it a SIGHUP(If the shell receives a SIGHUP, it also sends a SIGHUP to the process, which normally causes the process to terminate).
And obviously, it can only be applied to background jobs(because you cannot enter it when a foreground job is running).
nohup disconnects the process from the terminal, redirects its output to nohup.out and shields it from SIGHUP.
The process won't receive any sent SIGHUP.
Its completely independent from job control and could in principle be used also for foreground jobs(although that's not very useful).
Usually used with &(as a background job).
nohup cmd
doesn't hangup when you close the terminal. output by default goes to nohup.out
You can combine this with backgrounding,
nohup cmd &
and get rid of the output,
nohup cmd > /dev/null 2>&1 &
you can also disown a command. type cmd, Ctrl-Z, bg, disown
Alternatively, after you got the program running, you can hit Ctrl-Z which stops your program and then type
bg
which puts your last stopped program in the background. (Useful if your started something without '&' and still want it in the backgroung without restarting it)
screen -m -d $command$ starts the command in a detached session. You can use screen -r to attach to the started session. It is a wonderful tool, extremely useful also for remote sessions. Read more at man screen.

why background process group die when terminal closed

According to this faq (and by many other books):
ftp://rtfm.mit.edu/pub/faqs/unix-faq/programmer/faq
1.15 Why doesn't my process get SIGHUP when its parent dies?
SIGHUP won't be sent to background processes when none of them is " stopped ".
but we all know that if SIGHUP isn't captured in background processes, they will die when you close the terminal(or connection like ssh).
i.e. CTRL+Z - bg isn't enough for a process to survive when terminal is closed.
But why?
Any wisdom is appreciated!
There is an easy solution for it. Use nohup before running the command.
After googling a bit.
I assume the HUP signal which result in exiting of background processes is from shell.
Here are the steps:
Terminal is closed, bash receives SIGHUP from kernel(driver)
Bash exits by default upon receipt of a SIGHUP. Before exiting, it resends the SIGHUP to all jobs, running or stopped
All jobs, including background processes, exit if they don't capture SIGHUP

Resources