Running a bash script in the background with job control enabled and stdin closed will exit the PARENT shell. How can that happen?
To demonstrate make this background_bash_script
:
#!/bin/bash
set -m
ruby -e "puts :here"
Then run it in bash - it will exit the shell you ran it in. The ruby command does not matter although it appears it must be a command and not a bash built-in (for example awk --version
works but true
does not). To get a better look I've been running it in yet another instance of bash. A full session looks like this.
parent: PS1='child: ' bash
child: ./background_bash_script <&- &
[1] 3893
child: here
exit
parent:
Confusing!
What seems like is happening is that after set -m
is run in the script, the next command that is run is forced to be in the foreground process group, which takes the original shell out of the foreground process group. Once that process exits, the shell running the script is now in the foreground process group, but once that shell exits, the original shell doesn't put itself back into the foreground process group because it ran the script in the background. So you now have an interactive shell that is in a background process group.
You can see some weird behavior here if you put a sleep at the end of your script so that it doesn't exit immediately. When you run the script in the background you get the terminal prompt back, but now your interactive shell isn't in the foreground process group! As soon as you try to type anything the shell exits. I'm not sure exactly what mechanism causes the exit. Since the shell is in the background, any attempts to read or write characters to the terminal should result in SIGTTIN OR SIGTTOU, but these signals don't cause the shell to exit in my tests.