16

I'd like to run and configure a process similarly to a daemon from a script.
My shell is zsh emulated under Cygwin and the daemon is SFK, a basic FTP server.

For what matters here, the script startserv.sh can be drafted as follows:

#!/bin/sh
read -s -p "Enter Password: " pw
user=testuser
share=/fshare
cmd="sfk ftpserv -user=$user -pw=$pw -usedir $share=$share"
$cmd &

After running the script startserv.sh, it stops (ends?) without showing any prompt, then:

  • CTRL+C ends both the script and the background job process;

  • Hitting Enter the script ends the process remains in the background.

Anyway I can see it only via ps and not jobs, so, when I want to close the process, I have to send a brutal kill -9 signal, which is something I'd like to avoid in favour of CTRL+C.

An alternative would be running the whole script in background. 'Would be', but the read command is unable get the user input if the script is run as startserv.sh &.

Note that I need an ephemeral server, not a true daemon: that is, I want the server process to run in the background, after the script ends, to perform simple interactive shell tasks (with a virtual machine guest), but I don't need the process to survive the shell; therefore nohup seems not appropriate.

2
  • get the process id of the process running in the background using bgproc="$!" and then command "$bgproc" to take the appropriate action. See also stackoverflow.com/questions/1908610/… Commented Oct 23, 2014 at 13:58
  • you can also make a PID file. Then read that file to see what process number it is and go from there.
    – jgr208
    Commented Oct 23, 2014 at 16:07

1 Answer 1

21

Hitting Enter the script ends the process remains in the background.

Almost! Actually, the script has already exited by the time you press Enter. However, that's how you can get your prompt back (because your shell prints its $PS1 all over again).

The reason why hitting Ctrl + C terminates both of them is because the two of them are linked. When you execute your script, your shell initiates a subshell in which to run it. When you terminate this subshell, your background process dies, probably from a SIGHUP signal.

Separate the script, the background process and the subshell

Using nohup, you might be able to get rid of this little inconvenience.

#!/bin/sh
read -s -p "Enter Password: " pw
user=testuser
share=/fshare
cmd="sfk ftpserv -user=$user -pw=$pw -usedir $share=$share"
nohup $cmd &

The disown alternative

If you can switch from /bin/sh to /bin/bash, you can give a try to disown as well. To know more, just type help disown in a bash instance.

disown -h $cmd &

Killing the background process "nicely"

Now, when it comes to killing your process, you can perfectly do a "Ctrl + C" using kill. Just don't send a brutal SIGKILL. Instead, you could use:

$ kill -2 [PID]
$ kill -15 [PID]

Which will send a nice SIGINT (2) or SIGTERM (15) to your process. You may also want to print the PID value after starting the process:

...
nohup $cmd &
echo $!

... or even better, make the script wait for a SIGINT, and send it back to the background process (this will keep your script in the foreground though):

#!/bin/sh
read -s -p "Enter Password: " pw
user=testuser
share=/fshare
cmd="sfk ftpserv -user=$user -pw=$pw -usedir $share=$share"
nohup $cmd &

# Storing the background process' PID.
bg_pid=$!

# Trapping SIGINTs so we can send them back to $bg_pid.
trap "kill -2 $bg_pid" 2

# In the meantime, wait for $bg_pid to end.
wait $bg_pid

If a SIGINT isn't enough, just use a SIGTERM instead (15) :

trap "kill -15 $bg_pid" 2 15

This way, when your script receives a SIGINT (Ctrl + C, kill -2) or a SIGTERM while waiting for the background process, it'll just relay the signals to it. If these signals do kill the sfk instance, then the wait call will return, therefore terminating your script as well :)

3
  • 1
    +1 Very informative. Since the script runs in a subshell, is there any possibility of accessing from the script to the job table of the script's parent shell? That is list jobs issuing jobs in the terminal after the script ends (instead of ps).
    – antonio
    Commented Oct 24, 2014 at 11:27
  • 1
    Jobs are associated to your current shell, they are not transmitted from one shell to another. When your subshell dies, its jobs are not recovered. By printing your background process' PID, you make sure you can get information about it easily even after the subshell has terminated (pid -p). Commented Oct 24, 2014 at 11:32
  • nice explanation, however if your script contains more commands, they never get executed (because of the wait). If you remove the wait, then the signal handling is broken :/
    – chefarov
    Commented Oct 7, 2018 at 17:58

You must log in to answer this question.

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