15

I have a script (lets call it parent.sh) that makes 2 calls to a second script (child.sh) that runs a java process. The child.sh scripts are run in the background by placing an & at the end of the line in parent.sh. However, when i run parent.sh, i need to press Ctrl+C to return to the terminal screen. What is the reason for this? Is it something to do with the fact that the child.sh processes are running under the parent.sh process. So the parent.sh doesn't die until the childs do?

parent.sh

#!/bin/bash
child.sh param1a param2a &
child.sh param1b param2b &
exit 0

child.sh

#!/bin/bash
java com.test.Main 
echo "Main Process Stopped" | mail -s "WARNING-Main Process is down." user@email.com    

As you can see, I don't want to run the java process in the background because i want to send a mail out when the process dies. Doing it as above works fine from a functional standpoint, but i would like to know how i can get it to return to the terminal after executing parent.sh.

theGuardian
  • 439
  • 2
  • 6
  • 17
  • 2
    Does it need to be ctrl-c or does hitting enter get you a prompt too? What does `ps` say is running at the point where you hit ctrl-c? – Etan Reisner Feb 02 '15 at 15:54
  • 2
    Is the java program expecting any input? Does it help if you change it to `java com.test.Main < /dev/null`? – arco444 Feb 02 '15 at 15:54
  • @ arco, the java program does take input, so that is not an option @Etan - it must be Ctrl C, ps says the 2 java processes are running and parent.sh – theGuardian Feb 02 '15 at 15:59
  • 4
    Add a `> /dev/null` at the end of the line with `mail`. `mail` will otherwise try to start its interactive mode. – Sebastian Stigler Feb 02 '15 at 16:03
  • 1
    @theGuardian, if it takes input, how do you expect it to background itself? It necessarily has a controlling terminal handle. – Charles Duffy Feb 02 '15 at 16:32
  • Does pressing enter also display your prompt when this happens, or is it only ctrl+c? – Charles Duffy Feb 02 '15 at 16:36
  • 1
    As @CharlesDuffy says, if the script takes input how can it run in the background? Where is it going to get its input from? You aren't supplying it any (and you kill it with ctrl-c, I'd expect you to have to hit it twice actually). – Etan Reisner Feb 02 '15 at 17:34
  • The usual answer for this (if you *must* read input from the terminal before daemonizing, rather than getting that input via the command line or environment) is to have it first read its input then self-daemonize, which involves closing all its handles on the terminal (replacing stdin, stdout and stderr with handles on `/dev/null`), calling setsid() to create a new session, and doing a double fork. – Charles Duffy Feb 02 '15 at 20:22

3 Answers3

10

What i ended up doing was to make to change parent.sh to the following

#!/bin/bash
child.sh param1a param2a > startup.log &
child.sh param1b param2b > startup2.log &
exit 0

I would not have come to this solution without your suggestions and root cause analysis of the issue. Thanks!

And apologies for my inaccurate comment. (There was no input, I answered from memory and I remembered incorrectly.)

theGuardian
  • 439
  • 2
  • 6
  • 17
  • 2
    I experienced the same problem and this worked for me. Replacing `&` with `> /dev/null &` also works if you don't need to collect the output. – Mahn Apr 16 '16 at 23:05
8

The following link from the Linux Documentation Project suggests adding a wait after your mail command in child.sh:

http://tldp.org/LDP/abs/html/x9644.html

Summary of the above document

Within a script, running a command in the background with an ampersand (&) may cause the script to hang until ENTER is hit. This seems to occur with commands that write to stdout. It can be a major annoyance.

....
....

As Walter Brameld IV explains it:

As far as I can tell, such scripts don't actually hang. It just seems that they do because the background command writes text to the console after the prompt. The user gets the impression that the prompt was never displayed. Here's the sequence of events:

  1. Script launches background command.
  2. Script exits.
  3. Shell displays the prompt.
  4. Background command continues running and writing text to the console.
  5. Background command finishes.
  6. User doesn't see a prompt at the bottom of the output, thinks script is hanging.

If you change child.sh to look like the following you shouldn't experience this annoyance:

#!/bin/bash
java com.test.Main
echo "Main Process Stopped" | mail -s "WARNING-Main Process is down." user@gmail.com
wait

Or as @SebastianStigler states in a comment to your question above:

Add a > /dev/null at the end of the line with mail. mail will otherwise try to start its interactive mode.

This will cause the mail command to write to /dev/null rather than stdout which should also stop this annoyance.

Hope this helps

Marc.2377
  • 7,807
  • 7
  • 51
  • 95
ptierno
  • 9,534
  • 2
  • 23
  • 35
  • OP can also add the `wait` command after the last call to `child.sh` (right before `exit 0` and the effect will be the same. – Marc.2377 Dec 19 '19 at 09:17
8

The process was still linked to the controlling terminal because STDOUT needs somewhere to go. You solved that problem by redirecting to a file ( > startup.log ).

If you're not interested in the output, discard STDOUT completely ( >/dev/null ).

If you're not interested in errors, either, discard both ( &>/dev/null ).

If you want the processes to keep running even after you log out of your terminal, use nohup — that effectively disconnects them from what you are doing and leaves them to quietly run in the background until you reboot your machine (or otherwise kill them).

nohup child.sh param1a param2a &>/dev/null &
dashnick
  • 2,020
  • 19
  • 34
Tim
  • 751
  • 8
  • 11