Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

the manuals fail me

by Anonymous Monk
on Mar 28, 2012 at 21:06 UTC ( [id://962258]=perlquestion: print w/replies, xml ) Need Help??

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

I am trying to learn perl, and am trying to implement something simple: reading, updating, then writing an index value to a file. This is what it would be in bash:

index = `cat /tmp/myfile.index` $index = $index + 1 echo $index > /tmp/myfile.index exit 0

This is what I think I need to do in perl (comments about specific lines of code follow the code):

if(! -e "/tmp/test.index") { system("/usr/bin/touch /tmp/test.index"); } #This first test is necessary because if I add the creation permission + to the open command, it clobbers the file, preventing me from readin +g from it open(FILE, "+</tmp/test.index") || die $!; $index = <FILE>; #printing out the value of $index leads me to believe that this part w +orks if( ! $index =~ /[0-9]+/ ) { $index = 1; } #This should handle any sort of corruption to the file $i++; truncate(FILE, 0); #I do this to be safe. But when I do, it prepends two null characters +. print FILE $index; #This command has no apparent effect. close(FILE); exit 0;

Help?

Replies are listed 'Best First'.
Re: the manuals fail me
by jwkrahn (Abbot) on Mar 28, 2012 at 21:17 UTC
    index = `cat /tmp/myfile.index` $index = $index + 1 echo $index > /tmp/myfile.index exit 0

    In Perl you would write that as:

    $index = `cat /tmp/myfile.index`; $index = $index + 1; system "echo $index > /tmp/myfile.index"; exit 0;
Re: the manuals fail me
by ikegami (Patriarch) on Mar 29, 2012 at 01:11 UTC
    use Fcntl qw( LOCK_EX O_RDWR O_CREAT SEEK_SET ); my $qfn = '/tmp/myfile.index'; sysopen(my $fh, $qfn, O_RDWR|O_CREAT, 0666) or die("Can't create or open \"$qfn\": $!\n"); flock($fh, LOCK_EX); my $index = <$fh>; ++$index; seek($fh, 0, SEEK_SET); print($fh "$index\n"); #truncate($fh, tell($fh));

    You could also do it without locking:

    my $qfn = '/tmp/myfile.index'; open(my $fh, '<', $qfn) or die("Can't open \"$qfn\": $!\n"); my $index = <$fh>; ++$index; open($fh, '>', $qfn) or die("Can't create \"$qfn\": $!\n"); print($fh "$index\n");
      The locking method appeals to me. Could you tell me what LOCK_EX should do, and which version of fcntl you use with it? My manpage does not mention it, and google is not helpful.
        ...and Perl only provides one flock, so no idea what "version of fcntl" means.
        LOCK_EX is an exlusive lock. See man flock(2)
Re: the manuals fail me
by jwkrahn (Abbot) on Mar 28, 2012 at 21:51 UTC

    You could perhaps do it like this:

    use Tie::File; my $filename = '/tmp/myfile.index'; tie my @index, 'Tie::File', $filename or die "Cannot open '$filename' +because: $!"; ++$index[ 0 ]; untie @index;
Re: the manuals fail me
by JavaFan (Canon) on Mar 28, 2012 at 21:21 UTC
    You wouldn't write $index = $index + 1 in bash.

    Here's some untested code in Perl:

    use autodie; use Fcntl qw[:DEFAULT :seek]; sysopen my $fh, "/tmp/text.index", O_RDWR | O_CREATE, 0666; my $count = <$fh> || 0; seek $fh, 0, SEEK_SET; truncate $fh; print $fh $count + 1; close $fh;
    Or use a precanned CPAN solution.
Re: the manuals fail me
by JavaFan (Canon) on Mar 28, 2012 at 21:26 UTC
    Here's a bash one-liner:
    echo $((`cat /tmp/myfile.index 2> /dev/null` + 1)) > /tmp/myfile.index
      That's a nifty but subtle and tricky solution. Normally, when a shell command ends with redirection to a file like that, and the same file name is also used as input at a previous step in the same command line, the file gets truncated first (the redirect/truncation is processed before the preceding steps are launched), so the the earlier input step ends up reading an empty file.

      My mind boggles at how much of the bash man page must be studied to understand why your command line works the way it does, executing the double-paren'd chunk before truncating the output file. And I feel sorry for anyone who looks at that line, concludes that it's a simple and normal thing to use the same file as input and redirection output in a single command, and forgets about the parens.

Re: the manuals fail me
by rovf (Priest) on Mar 29, 2012 at 10:31 UTC
    Since you seem to be on Unix/Linux or compatible:

    perl -pi -e '++$_' /tmp/myfile.index

    -- 
    Ronald Fischer <ynnor@mm.st>
Re: the manuals fail me
by Util (Priest) on Mar 28, 2012 at 21:59 UTC

    I think it is clearer and less error-prone to open the file twice (input, then clobber and output) instead of opening once in read-and-write mode.
    Working, tested code:

    #!perl use strict; use warnings; my $filename = '/tmp/test.index'; my $index = 0; if ( -e $filename ) { open my $input_fh, '<', $filename or die "Failed to open '$filename' for input: $!"; my $line = <$input_fh>; if ( not eof $input_fh ) { die "File '$filename' has more than one line! Dying to avoid c +lobbering unexpected contents."; } close $input_fh or warn; chomp $line; $index = $line; } $index++; open my $output_fh, '>', $filename or die "Failed to open (and clobber) '$filename' for output: $!"; print {$output_fh} $index, "\n"; close $output_fh or warn;

Re: the manuals fail me
by MidLifeXis (Monsignor) on Mar 29, 2012 at 12:41 UTC

    All responses (at this point in time) except for ikegami's (++, BTW) do not mention locking. If you will be accessing this file simultaneously by multiple processes, you will want to use a locking solution, or you face a race condition.

    --MidLifeXis

Re: the manuals fail me
by Anonymous Monk on Mar 29, 2012 at 14:01 UTC
    Thanks, all. That gives me many ideas.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://962258]
Approved by ww
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others rifling through the Monastery: (10)
As of 2024-04-24 09:46 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found