Flubb has asked for the wisdom of the Perl Monks concerning the following question:
Hullo Venerable Monks:
The program below opens a file, reads the last two lines, looks for a number, increments that number, then (I hope) appends the new lines to the bottom of the file.
When I open $file for reading (and only reading) the program works, and prints out the new line to the screen. Making it read/write (+>>$file) gives me:
Use of uninitialized value in pattern match (m//)...at line 15
I'm not sure why the simple addition of making the file read and writable empties my $line1 variable (opening with >$file destroys the file completely). Any clues?
Full code bit:
------------------------
#!/usr/local/bin/perl -w
use strict;
my($newline);
my($file) = "d:\\softdev\\Pserver.txt";
my(@lines);
my($lines);
my($line1);
my($line2);
open (DAT, "+>>$file") or die "$!";
@lines = <DAT>;
$line1 = $lines[-1];
$line2 = $lines[-2];
if ($lines[-1] =~ /(\d)/){
$newline = ($1 + 1);
print "$newline\n";
$line1 =~s/(\d)/$newline/;
print "$line1\n";
print DAT "$line1";}
close DAT;
-------------------------
(It's probably ugly code, but I'm self-taught and have no Compsci background :F)
Cheers,
Flubb
Re: Filehandles vs Uninitialized Values in pattern match
by Sidhekin (Priest) on Nov 23, 2007 at 16:04 UTC
|
The +>> mode puts the file position initially at eof, so there is nothing left to read. Your @lines will be empty. (And hence, $lines[-1] etc will be undefined.)
If I read your intentions correctly, you seem to be missing just a seek DAT, 0, 0 before you read from the file. (See seek; in short it sets file position to start of file.)
(The file position will be advanced as you read, so ending up at eof afterwards, but even if it wasn't, opening with +>> makes sure Perl will seek to eof before starting to output anything on the handle.)
print "Just another Perl ${\(trickster and hacker)},"
The Sidhekin proves Sidhe did it!
| [reply] [d/l] [select] |
Re: Filehandles vs Uninitialized Values in pattern match
by johngg (Canon) on Nov 23, 2007 at 16:18 UTC
|
You might find it useful to have a look at Tie::File. This allows you to treat a file just as if it was an array. Thus, adding new lines at the end of the file is as simple as pushing onto the array. If the file is large you might not get great performance so YMMV.I hope this is useful. Cheers, JohnGG | [reply] |
|
If the file is large you might not get great performance so YMMV.
That's probably not going to be much of an issue as (quoth the manual)
The file is not loaded into memory, so this will work even for gigantic files.
I don't know if Tie::File seeks from the end for large/negative indexes, but it's surely possible for it to do so.
I just read the code... please ignore.
-David
| [reply] [d/l] |
Re: Filehandles vs Uninitialized Values in pattern match
by naikonta (Curate) on Nov 23, 2007 at 16:35 UTC
|
#!/usr/bin/perl
use strict;
use warnings;
my($rdwr_file, $tie_file) = @ARGV;
with_rdwr();
with_tiefile();
sub with_rdwr {
open DAT, "+<$rdwr_file" or die "can't open $rdwr_file: $!\n";
my $last = (<DAT>)[-1];
if ($last =~ /(\d+)/) {
my $new = $1 + 1;
seek DAT, 0, 2 or die "Can't seek in $rdwr_file: $!\n";
print DAT $new, "\n";
print "new value for $rdwr_file: $new\n";
}
close DAT;
}
sub with_tiefile {
use Tie::File;
my @lines;
tie @lines, 'Tie::File', $tie_file or die "can't tie $tie_file: $!
+\n";
my $last = $lines[-1];
if ($last =~ /(\d+)/) { # sure, testing on $lines[-1] saves a line
my $new = $1 + 1;
push @lines, $new;
print "new value for $tie_file: $new\n";
}
untie @lines;
}
The run:
$ echo 0 > rdwr
$ echo 0 > tie
$ cat rdwr
0
$ cat tie
0
$ perl prog.pl rdwr tie
new value for rdwr: 1
new value for tie: 1
$ cat rdwr
0
1
$ cat tie
0
1
... and some executions later..
$ cat rdwr
0
1
2
3
4
5
$ cat tie
0
1
2
3
4
5
Open source softwares? Share and enjoy. Make profit from them if you can. Yet, share and enjoy!
| [reply] [d/l] [select] |
Re: Filehandles vs Uninitialized Values in pattern match
by HuckinFappy (Pilgrim) on Nov 23, 2007 at 16:21 UTC
|
open (DAT, "+>>$file") or die "$!";
You aren't just opening the file read/write, you're opening it read/write in *append* mode. That means the pointer is at the end of the file when you open it. So when you read it, you don't get anything. There are a few things you can try here to learn a little more. Here's a little debugger session I played with that might help you get this working correctly. There's also some other things I do differently here that you may wish to adopt as standard practices, such as using a lexical filehandle and 3-argument form of open:
DB<1> open $fh, '+>>', 'test.dat'
+
+
DB<2> if ( eof $fh ) { print "Don't try to read, you're at the end!\
+n" }
+
Don't try to read, you're at the end!
DB<3> seek $fh, 0, 0
+
+
DB<4> if ( not eof $fh ) { print "Read on, McDuff!\n" }
+
+
Read on, McDuff!
DB<5> @lines = <$fh>
+
+
DB<6> x @lines
DB<7> chomp @lines
+
+
0 'First Line'
1 'Second Line'
2 'Last Line'
Hope this helps,
~Jeff
| [reply] [d/l] [select] |
Re: Filehandles vs Uninitialized Values in pattern match
by angiehope (Pilgrim) on Nov 23, 2007 at 16:16 UTC
|
Hi!
Reading the perldoc documentation on open, I found that "+<" was recommended for reading from and writing to files, as "+>" would clobber the file first.
open (DAT, "+<$file") or die "$!";
worked on my linux machine (I haven't tested this on Windows though).
Have a nice weekend! | [reply] [d/l] |
Re: Filehandles vs Uninitialized Values in pattern match
by zer (Deacon) on Nov 23, 2007 at 16:10 UTC
|
'+<' is a better option. It will read the file as it normally would then leaves the file pointer at the end so you can append.
UpdateSidhekin is right in saying that +>> is clearer to read, however seek can be just as confusing if youve never dealt with it before. | [reply] |
|
'+<' is a better option
+< is another option, to be sure, but better? +>> states your intentions to read and append. +< leaves it open whether or not you intend to overwrite any of the original contents.
It would save you a seek, sure, but at a cost of clarity. TIMTOWTDI, indeed, but I think Flubb had the right idea.
print "Just another Perl ${\(trickster and hacker)},"
The Sidhekin proves Sidhe did it!
| [reply] [d/l] [select] |
Re: Filehandles vs Uninitialized Values in pattern match
by Flubb (Acolyte) on Nov 26, 2007 at 12:11 UTC
|
Thanks everyone :) I'd add kudos points if I could.
The "+<" option definitely works. I'll have a check on the others later.
o/
Flubb | [reply] |
|
|