This usually happens if the process tries to read from its stdin
stream. When the process is in the background, it receives a TTIN signal and is thus frozen (same behavior as a STOP signal). There is also the dual signal TTOU when a background process tries to write to its terminal.
Bringing it to the foreground resumes the process and allows it to read from your terminal.
Demo:
$ cat t.sh
#! /bin/sh
sleep 1
read dummy
$ ./t.sh &
[1] 3364
$
[1]+ Stopped ./t.sh
$ ps aux|grep t.sh
me 3364 0.0 0.0 11268 1200 pts/0 T 17:04 0:00 /bin/sh ./t.sh
One of the ways of avoiding this is to use nohup
, but this can have strange effects if the program doesn't deal with having its input stream redirected to /dev/null
.
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 wait
ing 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 :)
Best Answer
You got the prompt back (see the fifth line of your code block) — and then you got the output. You were still "at the shell prompt" when you typed Enter the third time.
In theory, the shell could be programmed to reissue the prompt when a background process terminates. But
echo 1
and the1
appeared on your terminal, your cursor went back to the left edge of the screen, and it became non-obvious that you were still "at the shell prompt". And the foreground shell doesn't know when a background task writes to the screen.Historically, the shell doesn't know when you're typing a command; it knows only when you type Enter. (That may still be the case in some contexts.) So the shell wouldn't know if you were in the middle of typing a third command
and it would be really confusing if you got a new shell prompt when you were in the middle of typing a command.