views:

365

answers:

4

I've got a function that does (in short):

my $file = IO::File->new("| some_command >> /dev/null 2>&1") 
    or die "cannot open some_command for writing: $!\n";
...
undef $file;

Right now I'm not even writing anything to $file. Currently there are no other operations on $file at all. When I run the program, it doesn't exit properly. I see that handle is closed, but my program is still waiting for the process to close. Captured with strace:

close(6)                                = 0
rt_sigaction(SIGHUP, {SIG_IGN}, {SIG_DFL}, 8) = 0
rt_sigaction(SIGINT, {SIG_IGN}, {SIG_DFL}, 8) = 0
rt_sigaction(SIGQUIT, {SIG_IGN}, {SIG_DFL}, 8) = 0
wait4(16861, ^C <unfinished ...>

I don't see this problem if I open the same process for reading.

What do I have to do to make the program to exit?

Edit: Suggestions so far were to use the Expect library or to finish the input stream via ctrl+d. But I do not want to interact with the program in any way at this point. I want it to finish exactly now without any more IO going on. Is that possible?

+6  A: 

If some_command is waiting for input, it will likely sit there forever doing just that, waiting for input.

From what the docs say, I don't think it makes any difference, but I always do $file->close() instead of/before undef'ing the handle.

EDIT: Send it Control D? Perhaps some_command is reading tty's instead of stdin, like passwd does. If you are in that realm, I'd suggest looking up Expect.

Control D simply duplicates the zero byte read that close should do anyway for a command line program.

Have you tried using $file->close() instead of the undef?

Daren Schwenke
Yes, it does wait for input. How can I ensure that the program is closed if I only have that file handle available?
viraptor
It does have a prompt. And I don't want/need the `expect` functionality. I'd like to simply force that process to exit. I don't want to send anything to the process, as I don't know what state is it in (and therefore what will CTRL+d do). I'm ok with killing the process and do not want it to do any more processing at that point.
viraptor
Just to be more specific - It would be perfect if the process was killed. I do not want it act in any way when the pipe to my program is disconnected.
viraptor
A: 

Does some_command slurp all input and process it? Such as grep? Or does it prompt? Like, say... chfn? Does it return any useful information? Like an indication that it's finished?

If it's the latter, you might want to read up on Expect so you that you can interact with it.

EmFi
It does have a prompt. And I don't want/need the `expect` functionality. I'd like to simply force that process to exit.
viraptor
+8  A: 
mobrule
A: 

This ugly, ugly hack will cause some_command to be parented to init instead of staying in your perl's process tree. Perl no longer has any process to wait for, and the pipe still works -- yay UNIX.

my $file = IO::File->new("| some_command >> /dev/null 2>&1 &")

Cons: The shell will succeed at & even if some_command fails, so you won't get any errors back.

    or die "cannot open some_command for writing: $!\n";  # now useless

If some_command exited as soon as it got an EOF on stdin (and never stops reading from stdin), though, I'd expect this wouldn't be necessary.

$ cat | some_command
^D

Does that hang, and can you fix that?

ephemient