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

Hi, I've inherited a bit of perl code which unfortunatley uses an in-place edit.
if ($delrec) { local $^I = ".keep"; @ARGV = qw(filename); while (<>) { do stuff } }
I'm fully aware of the dangers of using $^I however I'm not able to change that at present for reasons I can't go into. What I would like to do is to flock the file when it is opened. How do I do this when in-place edit is being used in this manner ?

Replies are listed 'Best First'.
Re: flock on on $^I
by thundergnat (Deacon) on Aug 18, 2010 at 13:36 UTC
    I'm not able to change that at present for reasons I can't go into.

    How do I survive jumping out of a highflying aircraft without using a free, easily available parachute? Sigh. Sounds more like a political problem than a perl problem.

    Anyway. Look in "perldoc perlrun" under -i to see the demo equivalent of inplace editing, then reimplement including the desired changes. You're stuffing the filename into @ARGV not passing it in from the command line, and there's only one at a time, so those aren't a problem. I don't really see why you are so tied to the default implicit behaviors.

Re: flock on on $^I
by repellent (Priest) on Aug 18, 2010 at 17:55 UTC
    Try to flock the ARGVOUT filehandle in the while loop. See perlvar for the description of ARGVOUT.

    Update: I meant ARGVOUT instead of ARGV.
Re: flock on on $^I
by Khen1950fx (Canon) on Aug 19, 2010 at 00:47 UTC
    I tried this with constraints: I didn't want to use -i nor $^I.

    Requirements:

    File::Inplace
    File::Flock.

    A dir "in_place"
    A file "abc.txt".
    A file "adc.txt".
    Both files should be in the dir "in_place".

    #!/usr/bin/perl use strict; use warnings; use File::Copy; use File::Inplace; use File::Spec; use File::Flock; my $dir = '/root/Desktop/in_place'; my $data_dir = sub { File::Spec->catfile($dir, shift); }; my $abc_file = "/root/Desktop/in_place/abc.txt"; my $adc_file = "/root/Desktop/in_place/adc.txt"; lock($abc_file, 'shared', 'nonblocking'); lock($adc_file, 'shared', 'nonblocking'); my $edit = new File::Inplace(file => $data_dir->("abc.txt"), suffix => + ".log"); quick_change($edit, hello => 'jello'); $edit->commit; my $lock = File::Flock->new($edit); lock($lock, 'abc.txt.log'); lock_rename($lock, 'abc.txt.log'); unlock('abc.txt.log'); sub quick_change { my $edit = shift; my $from = shift; my $to = shift; while ($edit->has_lines) { my $line = $edit->next_line; if ($line eq $from) { $edit->replace_line($to); } } }
    abc.txt:
    hello
    adc.txt:
    jello
      I had a go at doing it this way using a semaphore file. But I'm running into problems and can't figure out what is wrong.
      sub filelock; filelock "lockit"; Do the inplace edit stuff here filelock "unlock"; sub filelock { if ( @_ eq "lockit" ) { open(LCK,">abc.lock") or die "Can't open abc.lock: $! \n"; unless (flock LCK, LOCK_EX) { warn "Waiting to obtain lock on LCK ....\n"; flock(LCK, LOCK_EX) or die "Cannot lock semaphore file + - $!\n"; } } if ( @_ eq "unlock" ) { close(LCK) } }
      The problem is that it's not recognising "lockit" or "unlock" when the filelock subroutine is called. Even though when I print out @_ it displays "lockit" or "unlock" accordingly. What am I doing wrong ?
        fixed by adding this
        my $lockopt = shift; if ( $lockopt eq "unlock") { do stuff... }
        Being new to perl there's undoubtedly a better way of doing this !