LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (http://www.linuxquestions.org/questions/programming-9/)
-   -   bash `kill`: process 'B' silently dies; but process 'A' = `kill` spews back debris! (http://www.linuxquestions.org/questions/programming-9/bash-%60kill%60-process-b-silently-dies%3B-but-process-a-%3D-%60kill%60-spews-back-debris-734657/)

GrapefruiTgirl 06-21-2009 09:54 PM

bash `kill`: process 'B' silently dies; but process 'A' = `kill` spews back debris!
 
Yesss.... :confused:

I'm dealing with a couple weird little 'bash-isms' here this evening.

Here's the situation (the first one anyway):

Process 'A' is a forked off TAIL command, simply following a logfile and dumping the tailed output to another file.
When I fork it from the bash script, I grap the PID from '$!' and save it to a pidfile.

Process 'B' is a forked off function in this bash script, which again, after forking it I grab the PID and save it to a pidfile; like so (very simplified):

Code:


#!/bin/bash

silly_function_name () {
sleep 10000
blah blah
}

case $1 in
 start)
  tail -f /some/log > some/file &
  echo $! > pidfile_A
  silly_function_name &
    echo $! > pidfile_B
    ;;
 stop)
    kill `cat pidfile_A`
    kill `cat pidfile_B`
    ;;
esac;

exit 0

OK, so I run the script, which has a START and STOP argument I can send to it, like so:

sh# ./script start

..so far so good.

sh# ./script stop

..now, the crap: function fork dies silently with no feedback from `kill`; but killing the TAIL command fork returns the likes of:

Code:


[1] 35242  Terminated            tail -f /some/file  >some/other/file

to the console. I don't want that.

Now, I should mention that this effect does NOT happen if I start a tail fork from the command-line, and then kill it with `kill 1234` ; it dies silently with no feedback. But when I run the script, voila! ugly feedback from kill, but ONLY from killing the tail command, not from killing the function that was forked.

Also, I've tried directing STDERR and STDOUT to /dev/null or to a file, and I've tried trapping the feedback in a $variable, and I've tried piping it into other stuff, but nothing supresses the 'Terminated' message.

Anyone have any insight?

Heres situation 2:

Assuming the same script as above; the function in the script contains a 'sleep' command. When I start the script, and the function forks, I can look at `ps ax` and I can see the function's process itself, and I can also see that a sleep thread has been created by it. That's all fine and dandy, however when I stop the script, or kill the function with `kill 1234` the sleep thread remains in the ps list. It isn't zombified, it's 'sleeping'.
Why is it still there??
Since it was within the function, I like to think that killing the function itself, would terminate the sleep thread as well.

Why not??

:confused:

Sasha

GrapefruiTgirl 06-22-2009 08:22 AM

I have come up with a solution, or a work-around, for situation one.

by changing the `kill` statement to:

Code:

pid=`cat $pidfile`
kill $pid > /dev/null 2>&1 &
wait

the 'Terminated..' line is eliminated. Not sure if I need to background the kill statement (but in the real-life context in which it's being used, it works); the main issue was *probably/possibly* that I was doing the shell redirection improperly.

Situation TWO from my first post still astounds and amazes ;) and I haven't figured out why the `sleep` thread doesn't terminate when its parent process dies.

Sasha

bigearsbilly 06-22-2009 03:48 PM

plus, function is a keyword.

Code:

Functions are declared using this syntax:

    [ function ] name () compound-command [ redirections ]


GrapefruiTgirl 06-22-2009 07:50 PM

Thanks for the heads-up re: 'function'
 
Quote:

Originally Posted by bigearsbilly (Post 3582699)
plus, function is a keyword.

Code:

Functions are declared using this syntax:

    [ function ] name () compound-command [ redirections ]


Thanks Billy, I hadn't even thought of that.

In the real-world program I am working on, the function is not actually named 'function' -- that was a poor choice of function names in my example, and I have corrected it.

So, the sleep thread problem still exists as it did.

Sasha

norobro 06-22-2009 09:15 PM

I piddled (no pun intended) with this a little today and my sid system doesn't issue the warning when I run the stop option. I understand that your script is more complex than the description that you gave but it seems odd that Slackware and Debian would behave differently. Maybe it's a bash shell option like "notify" that is set differently. Dunno.

Here's the code that I ran (pretty much exactly like your example):
Code:

!/bin/bash

bar () { sleep 300; }

case $1 in
 start)
    tail -f /var/log/syslog > tail_output &
    echo $! > pidfile_A
    bar &
    echo $! > pidfile_B
    ;;
 stop)
    kill `cat pidfile_A`
    kill `cat pidfile_B`
    ;;
esac;
exit 0

Code:

./foo.sh start
ps -aux
user  10151  0.0  0.1  3100  552 pts/1    S    20:44  0:00 tail -f /var/log/syslog
user  10152  0.0  0.1  4864  960 pts/1    S    20:44  0:00 /bin/bash
user  10153  0.0  0.0  3076  504 pts/1    S    20:44  0:00 sleep 300

Code:

cat pidf*
10151
10152

Code:

./foo.sh stop
ps -aux
user  10089  0.0  0.4  4864  2072 pts/1    Rs  20:41  0:00 /bin/bash
user  10153  0.0  0.0  3076  508 pts/1    S    20:56  0:00 sleep 300

As I said, if stop is run there is no output. It kills two processes and leaves the sleep process running. My guess is that it has to spawn a shell in order to put the function in the background and that is what is captured with "$!". I don't think a normal function call is a process.

Really no solution offered above but I thought that I would share my experiences with you.

Finally to the point of my post: I did find some interesting discussion about killing parent and child processes right here on LQ (where else?) but I haven't tried any of the suggestions: link link

GrapefruiTgirl 06-22-2009 09:29 PM

@ norobro,

Thanks for taking the time to do some experimenting on the subject. It is most interesting: as we see, the same thing happens on your system regarding the sleep command/thread.. It stays alive until it times out. Weird. I could kill it, but sheesh, it's looking like I'm creating quite a pile of pidfiles to deal with, for one rather small script :)

As you speculated, possibly different versions of BASH are in play, or different BASH configurations on different systems. FWIW my current BASH is version 3.1.17(2), not the one that came with my Slack OS.

The outputs from the script when I stop/kill it are not really detrimental or serious, but I am super-detail-oriented, perhaps too much so sometimes (obsessive with detail ? :confused: ?) heh heh. Maybe I'm too picky; but something I find annoying is when a script has executed completely and returns the prompt to the user, then suddenly some more output spews forth from the remaining backgrounded process. I don't like it.

Well, it has been a long and tiresome day for me; I will have to look at those two threads you linked to above, but it will be tomorrow. I'm about thru for today.

Thanks again for the input and testing!

Sasha

bigearsbilly 06-23-2009 05:08 AM

well, on the command line
bash and ksh
both produce terminated whether backgrounded as
a function or as a straight command.

I tried the script (apart from changing it to #!/bin/bash ;)
and /var/log/messages -- I get no terminated messages.

when you call a function it spawns a new shell this is the number
returned in $!. sleep also spawns a new process. so you are killing the
shell not the sleep.

an interactive shell passes signals on to it's children, this would imply that a non-interactive
shell does not. I would assume a function to be a non interactive shell.

even though, if you do a sleep & and exit the shell it still doesn't die (the sleep)

the plit thockens

norobro 06-23-2009 09:26 AM

Quote:

Originally Posted by bigearsbilly (Post 3583183)
I tried the script (apart from changing it to #!/bin/bash ;)

This typo is a pretty easily caught. Think I should edit my post?
Quote:

Originally Posted by bigearsbilly (Post 3583183)
well, on the command line
bash and ksh
both produce terminated whether backgrounded as
a function or as a straight command.

Looking back, I misread or misunderstood GrapefruiTgirl's op. I thought that she was getting the terminated message from her script.

If you don't background the function and instead "bg" the sleep, GrapefruiTgirl's script works like a charm. So it seems that in order to "bg" something that doesn't normally require a separate process, bash has to spawn a shell. Thus creating the issue of being able to kill the parent process and all child processes.

GrapefruiTgirl 06-23-2009 09:39 AM

..something so simple.. er... not!
 
Quote:

Originally Posted by bigearsbilly (Post 3583183)
well, on the command line
bash and ksh
both produce terminated whether backgrounded as
a function or as a straight command.

.. and it's HARD to shut up the 'Terminated' message.. /dev/null doesn't seem to absorb it.

Quote:


I tried the script (apart from changing it to #!/bin/bash ;)
and /var/log/messages -- I get no terminated messages.
I get the impression you are subtly telling me something in the above, re: changing the shell statement to #!/bin/bash .. so? :)

Quote:

when you call a function it spawns a new shell this is the number
returned in $!. sleep also spawns a new process. so you are killing the
shell not the sleep.
Right.

Quote:


an interactive shell passes signals on to it's children; this [what we're learning here] would imply that a non-interactive
shell does not. I would assume a function to be a non interactive shell.
Sounds good to me, and seems correct.
Quote:


even though, if you do a sleep & and exit the shell it still doesn't die (the sleep)
Correct, the sleep does not die. It sleeps until it awakes, at which point it vaporizes. That's exactly what's pesky about this sleep thing.

Here's some console output to ponder (just executed in the console-- no deliberately spawned shells or scripts, and ignore the orange for a moment.). It's early here for me, so I'm not fully 'online' yet. :

Code:


sh-3.1# sleep 1000 &
[1] 23664
sh-3.1# kill 23664
sh-3.1#
[1]+  Terminated              sleep 1000

sh-3.1# sleep 1000 &
[1] 23704
sh-3.1# kill 23704 > /dev/null 2>&1
sh-3.1#
[1]+  Terminated              sleep 1000

sh-3.1# sleep 1000 &
[1] 23891
sh-3.1# kill 23891 > /dev/null 2>&1 &
[2] 23940
[1]-  Terminated              sleep 1000
[2]+  Done                    kill 23891 >/dev/null 2>&1


sh-3.1# sleep 1000 &
[1] 23971
sh-3.1# kill 23971 & > /dev/null 2>&1
[2] 24033
[1]-  Terminated              sleep 1000
[2]+  Done                    kill 23971
sh-3.1#

Notes/observations:
1) The line I bolded does not appear until I hit another keystroke (like pres RETURN at the prompt).
2) The 'Terminated' report is returned no matter what I do to try to hide it.

3) If I do the above examples from within a SCRIPT, the 'Terminated' report can be hidden, BUT:
3a) doing that like:
Code:

kill `cat $pidfile`
or
kill `cat $pidfile` &
wait

both spew back the Terminated line every time.. However, here's some in-script examples for comparison:
Code:

in-script examples 1 (returns 'Terminated' line no matter where/how I redirect output)
kill `cat $pidfile` > /dev/null 2>&1
kill `cat $pidfile` > /dev/null 2>&1 &

in-script example 2 (same result)
var=`cat $pidfile`
kill $var > /dev/null 2>&1

in-script example 3 (same result)
var=`cat $pidfile`
kill $var > /dev/null 2>&1 &

in-script example 4 (same result)
var=`cat $pidfile`
kill $var > /dev/null 2>&1 &

in-script example 5 (THIS HIDES the 'Terminated' line,
BUT ONLY if the wait command is after it, presumably
because the 'Terminated' message is delivered to the imaginary console
created by forking the KILL command, and the WAIT command
keeps output confined to that imaginary console, returning only
AFTER the 'Terminated' message has been displayed in that imaginary console;
This is the same as the orange example earlier.)
var=`cat $pidfile`
kill $var > /dev/null 2>&1 &
wait

In my real-life script, here's what it looks like (and it works great, despite being round-a-bout IMO).
note that elsewhere in the script, some_function () was forked, and $! was saved as $function_pid
Code:

sleep_pid=`ps ax | grep $(pgrep -P $function_pid) | gawk '{/^.[:digit:]+[ ]$/;print $1}'`
kill $function_pid > /dev/null 2>&1 &
wait;
kill $sleep_pid > /dev/null 2>&1 &
wait;

it works perfect.

I dunno if me or anyone can make much sense out of this post as a whole; as I said, it's early; I'm still on the first coffee.

Sasha

PS - I don't know how/why this thread is in the 'NON *NIX' programming forum.. Seems *NIXy enough to me.. :confused:

GrapefruiTgirl 06-23-2009 09:42 AM

Oh -- and @ norobro,

Those links you gave at the bottom of youe earlier post DID lead me to the working solution I have now in my actual real script. Some of the examples did NOT work for me as they did for the user(s) in those posts, but I managed to adjust what I read there and get a working result.

Link #2 was the more helpful to me. Thank you again.

Sasha


All times are GMT -5. The time now is 12:26 AM.