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 :)
Well, according to some of your edits you've got CTRL+J
bound to a bindkey
macro command. That explains your bash
issue considering readline
's default behavior.
Generally readline
reads input in something very like stty raw
mode. Input chars are read in as soon as they are typed and the shell's line-editor handles its own buffering. readline
sets the terminal to raw when it takes the foreground, and it restores it to whatever its state was beforehand when calling up another foreground process group.
CTRL+J
is an ASCII newline. ABCDEFGHIJ
is 10 bytes from NUL. Because you have configured readline
to eat this character and subsequently to expand away what remains of any command-line on which it does with menu-completion, type-ahead won't work. The terminal is in a different state when the type-ahead is buffered by the kernel's line-discipline than it is when readline
is in the foreground.
When readline
is in the foreground it does its own translation for input carriage returns -> newlines and the terminal driver doesn't convert it at all. When you enter your type-ahead input, though, the terminal driver will typically translate returns to newlines as can be configured with stty [-]icrnl
. And so your return key is sufficient for commands entered live, but the newlines sent by the terminal's line-discipline are being interpreted as menu-complete commands.
You might tell the terminal driver to stop this translation with stty -icrnl
. This is likely to take at least a little bit of getting used to. Other commands that accept terminal input will usually expect newlines rather than returns, and so you'll either have to explicitly use CTRL+J
when they control the foreground, or else teach them to handle the returns as bash
does.
You've already mentioned that read
doesn't work as expected when reading form the terminal. Again, it likely would if you explicitly used CTRL+J
to end an input line. Or... you can teach it:
read()
if [ -t 0 ]
then command read -d $'\r' "$@"
else command read "$@"
fi
It will probably be a lot less hassle in the long-run if you found a different key for menu-complete, though. Newlines are kind of a big deal for most terminal applications.
Best Answer
If you need the echo_to_prompt() command in a shell script or on the normal command line, you can simply use
read
:You can add the echo_to_prompt() function to your .bashrc/.profile/... if you want it on the command line.