Hi,<div><br></div><div>I'm Mike South, I live in McKinney and I telecommute for a company that's sort of based in Boston but actually headquartered in San Mateo.  I'm a long time perl developer, currently working in the operations group of a company that I had formerly done development for.  I'm doing a lot more scripting now (as opposed to application development) and learning a lot about infrastructure that I formerly only learned as much as I needed to solve whatever and get back to working on the application.</div>
<div><br></div><div>I was writing a diagnostic script the other day and I learned something that may be common knowledge but I thought I would share.</div><div><br></div><div>The code I was writing, which I will state at the outset should probably have used File::Tail from CPAN, sent a signal to a process and then watched a log waiting for a response to the signal to show up there.</div>
<div><br></div><div>There is not really a good reason to do it the way I did--I was just doing a straightforward implementation in script form of what I had been doing manually.</div><div><br></div><div>So, the manual process is like this:  kill -USR2 [process id].  Then tail -f ~/logs/error_log and wait for a response to show up there.  If it doesn't show a response after a while, control-c that tail and go do something else, if it does show a response, copy that and paste it into a file.</div>
<div><br></div><div>So, in the script, I sent the kill signal, then fork()ed, and in the child I used exec to start a tail -f redirected to an output file.</div><div><br></div><div>In the parent I looped for 60 tries (sleeping one second each time) seeing if there was anything in the output file (anything other than the few lines tail -f starts with by default, that is).</div>
<div><br></div><div>When I was done, either by giving up after 60 seconds or by seeing the output I was looking for, I wanted to be able to kill the tail -f.  My hope was that, by using exec (which replaces the running process with one doing whatever you told exec to do), the pid of the exec'd process would be the same as the pid I already knew from the fork call, so I would know what to kill.</div>
<div><br></div><div>That worked fine, several times.  But then one time, after running the script, when I went to log out it cleared the screen and just hung there.  Turned out that the tail -f process was still running. I checked the pid and it was one more than the child pid.  It seems that when you pass exec a string with shell metacharacters in it, (remember my tail -f was redirected to a file), exec will run a shell to parse those or something, and that ends up being a new process.</div>
<div><br></div><div>If you don't need the string to be interpreted by the shell, you can just pass each element of your command as a list (perldoc -f exec shows you that there are two ways to call it), and that seems, from other reports at least, to keep it from creating a new process.  But I needed shell interpretation for what I was doing so that didn't help me.</div>
<div><br></div><div>In a perlmonks thread I found while searching about this, one answerer recommended killing everything in the process group (except the parent, and then the parent can exit).  This is easy to do (lifted straight from the thread, except I added a missing semicolon):</div>
<div><br></div><div><div><font face="courier new, monospace">        my $pgrp_id=getpgrp(0); # gets the process group id of</font></div><div><font face="courier new, monospace">                                # the current process</font></div>
<div><font face="courier new, monospace"><br></font></div><div><font face="courier new, monospace">        { # scoping is important!  Otherwise</font></div><div><font face="courier new, monospace">          # that signal will always be ignored</font></div>
<div><font face="courier new, monospace">          # by the parent, which is probably bad.</font></div><div><font face="courier new, monospace">          # I picked SIGINT, you might prefer something</font></div><div><font face="courier new, monospace">          # else.</font></div>
<div><font face="courier new, monospace"><br></font></div><div><font face="courier new, monospace">            local $SIG{'INT'}='IGNORE';</font></div><div><font face="courier new, monospace">            kill 2, -$pgrp_id; # - means it's a group id.</font></div>
<div><font face="courier new, monospace">        }</font></div><div><font face="courier new, monospace">        warn "sent a sig int to the process group, you should ' ps auxww |grep tail ' to make sure that worked...\n";</font></div>
<div><br></div></div><div>There are many things that can be done better, like using IO::Select, or just plain seeking and reading on the file handle, etc, and when I looked just now I realized that someone else must have run into a need like this before, because tail has a command line argument that says "quit after process X is no longer active", which is exactly what I needed, and could even have just called it with system if I'd known that.</div>
<div><br></div><div>But I thought the information was interesting, and figured I would introduce myself and share.</div><div><br></div><div>mike</div>