http://www.perlmonks.org?node_id=714225

devnul has asked for the wisdom of the Perl Monks concerning the following question:

Pulling another all-nighter and am gettin' some unwanted behavior from File::Temp.. Anyone know what I'm missing?

OS is FreeBSD 6.2, PERL is 5.8.8, if that matters

Here is code which reproduces this unwanted behavior:
use strict; use File::Temp q/tempfile/; for(my $i=0;$i<50;$i++) { my $tmp = new File::Temp('DIR' => '/tmp', 'UNLINK' => 1); sleep(1); }

What is going on is that as this script runs I can run "ls -l /tmp" and see the files being created and destroyed. But as soon as I hit ctrl-C to quit, the last temp file it created is still hanging around (otherwise known as the "unwanted behavior").

I would note that removing 'UNLINK' => 1 from the constructor, or using the my ($fh, $filename) = tempname('DIR' => '/tmp', 'UNLINK' => 1); produces the same result. The only reason I changed it from that was in an attempt to debug what is going on.

- dEvNuL

Replies are listed 'Best First'.
Re: File::Temp.. What am I missing?
by chromatic (Archbishop) on Sep 29, 2008 at 03:47 UTC

    It makes sense to me; you're interrupting a running program before it has a chance to finish. If you want to perform the kind of cleanup that your program doesn't get to (thanks to the interruption), install a signal handler for SIGINT. Like graff suggests, you can install a signal handler. Here's an easier approach though:

    use strict; use warnings; use File::Temp 'tempfile'; $SIG{INT} = sub { exit }; for (0 .. 50) { my $tmp = File::Temp->new('DIR' => '/tmp', 'UNLINK' => 1); sleep(1); }

    With that change, the program will exit normally on SIGINT, rather than suffering an immediate exit. END and DESTROY code will run, which will clean up the temporary files.

Re: File::Temp.. What am I missing?
by graff (Chancellor) on Sep 29, 2008 at 03:38 UTC
    Try writing your loop like this:
    for(my $i=0;$i<50;$i++) { my $tmp = new File::Temp('DIR' => '/tmp', 'UNLINK' => 1); $SIG{INT} = sub { unlink "/tmp/".$tmp->filename; die }; ## <- add t +his line sleep(1); }
    Note that it's important to include the "die" call in the sub that gets assigned to $SIG{INT} -- otherwise, the script won't actually exit on ctrl-C.

    (Update -- to explain: when you interrupt the script, this will generally be during the sleep call, and unless you declare a signal handler to catch that, the File::Temp module will never get the chance to do its normal clean-up.)

    Another update -- check the perlipc docs, and your own system's manual regarding signals; you'll probably want to trap other things in addition to SIGINT (e.g. SIGTERM, which is what the shell "kill" command sends by default).

Re: File::Temp.. What am I missing?
by ikegami (Patriarch) on Sep 29, 2008 at 03:57 UTC
    On some systems (which should include FreeBSD), deleting the file while it's still open makes the file anonymous. It exists until the file no more file handles reference it.
    for (1..50) { my $tmp = File::Temp->new( DIR => '/tmp' ); # Make the file anonymous unlink($tmp); sleep(1); }

    The above is still vulnerable to Ctrl-C, but only for a tiny amount of time.

    By the way, did you notice how much more readable the Perl-style for loop syntax is over the C-style one you used?