tags:

views:

264

answers:

6

Im trying to extract part of a line with perl

use strict; 
use warnings;


# Set path for my.txt and extract datadir
my @myfile = "C:\backups\MySQL\my.txt";
my @datadir = "";

open READMYFILE, @myfile or die "Error, my.txt not found.\n";
    while (<READMYFILE>) {
        # Read file and extract DataDir path
        if (/C:\backups/gi) {
        push @datadir, $_;
        }
    }

# ensure the path was found
print @datadir . " \n";

Basically at first im trying to set the location of the my.txt file. Next im trying to read it and pull part of the line with regex. The error Im getting is:

Unrecognized escape \m passed through at 1130.pl line 17.

I took a look at http://stackoverflow.com/questions/1040657/how-can-i-grab-multiple-lines-after-a-matching-line-in-perl to get an idea of how to read a file and match a line within it, however im not 100% sure I'm doing this right or in the best way. I also seem to produce the error:

Error, my.txt not found.

But the file does exist in the folder C:\backups\MySQL\

+1  A: 

Use forward slashes instead of backslahes

frankc
Excellent, this took care of the "Unrecognized escape \m passed through at 1130.pl line 17." error, however Im still not getting the "Error, my.txt not found." still comes up for some reason.
perlnoob
+4  A: 

When Perl sees the string "C:\backups\MySQL\my.txt" it tries to parse any escape sequences, such as \n. But when it sees \m in \my.txt, it's an unrecognized escape sequence, hence the error.

One way to fix this is to properly escape your backslashes: "C:\\backups\\MySQL\\my.txt". Another way to fix this is to use single quotes instead of double quotes: 'C:\backups\MySQL\my.txt'. Yet another way is to use the q() construct: q(C:\backups\MySQL\my.txt).

Mark Rushakoff
I tried your solution aswell, it does work, however Im still having trouble with the "Error, my.txt not found.", but thanks so far!
perlnoob
@perlnoob: Are you absolutely sure that the file exists and is readable?
Mark Rushakoff
@Mark Rushakoff, yes, heres the output of that dir: Directory of C:\backups\mysql 04/09/2010 08:40 AM <DIR> . 04/09/2010 08:40 AM <DIR> .. 04/09/2010 08:45 AM 58 my.txt Even changing it to lowercase in the perl script yeilds no change. If I for example go to start > run and input: C:/backups/MySQL/my.txt, it opens up notepad with the text file
perlnoob
@perlnoob: Change your error message to include `$!` so that you see the error that the OS is actually returning when it fails to open the file.
Mark Rushakoff
@Mark Rushakoff, the solution Ryan Zachry has provided fixes this problem. Thanks for your help so far!
perlnoob
+1  A: 

Shouldn't you be using $myfile instead of @myfile? The latter gives you an array, and since you're referencing it in scalar context, it's getting dereferenced (so it's actually trying to open a "file" called something like ARRAY(0xdeadbeef) instead of the actual filename).

Alex
+1  A: 

The file is not being found because you are passing an array to open when it's expecting a scalar, so I'd guess that the array is being evaluated in a scalar context instead of as a list so you're actually telling perl to try opening the file named '1' instead of your 'my.txt' file.

Try something like this instead:

my $a = 'filename';
open FH, $a or die "Error, could not open $a: $!";
...
rayners
+3  A: 

Since there are several problems I'll put comments on the changes I've made in the code below.

use strict; 
use warnings;
# For pretty dumping of arrays and what not.
use Data::Dumper;

# Use single quotes so you don't have to worry about escaping '\'s.
# Use a scalar ($) instead of an array(@) for storing the string.
my $myfile = 'C:\backups\MySQL\my.txt';

# No need to initialize the array.
my @datadir;

# I believe using a scalar is preferred for file handles.
# $! will contain the error if we couldn't open the file.
open(my $readmyfile, $myfile) or die "error opening: $!";

while (<$readmyfile>) {
    # You must escape '\'s by doubling them.
    # If you are just testing to see if the line contains 'c:\backups' you do not
    # need /g for the regex. /g is for repeating matches
    if (/C:\\backups/i) {
        push(@datadir, $_);
    }
}

# Data::Dumper would be better for dumping the array for debugging.
# Dumper wants a reference to the array.
print Dumper(\@datadir);

Update:

If you're referring to the output from Data::Dumper, it's just there for a pretty representation of the array. If you need a specifically formatted output you'll have to code it. A start would be:

print "$_\n" for (@datadir);
Ryan Zachry
This did almost everything I wanted, however I was hoping to drop the quotes around the dir and the "DataDir=" portion of it, however so far this is the best answer.
perlnoob
+1  A: 

As other people have said, part of the issue is using " " rather than ' ' type of quoting. I try always to use ' ' unless I know I need to include an escape or interpolate a variable. Here are a number of pitfalls

    use 5.10.0 ;
    use warnings ;

    say "file is c:\mydir" ;
    say "please pay $100 ";
    say "on VMS the system directory is sys$system" ;
    say "see you @5 ";

With double quotes

    Unrecognized escape \m passed through at (eval 1) line 2.
    Possible unintended interpolation of @5 in string at (eval 1) line 5.
    file is c:mydir
    Use of uninitialized value $100 in concatenation (.) or string at (eval 1) line 3.
    please pay
    Use of uninitialized value $system in concatenation (.) or string at (eval 1) line 4.
    on VMS the system directory is sys
    see you

With single quotes

    file is c:\mydir
    please pay $100
    on VMS the system directory is sys$system
    see you @5
justintime