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

Hello, Newbie here,

I am trying to use a while loop to read through all of the values in a file, but the filenames contain an '@'.

I have the directory path in a variable, and the filenames in an array. So far I have tried using quotemeta to backslash special characters, which seems to print the correct values but this does not seem to work in my open command. I think maybe I have a problem with using the correct quoting??

Thanks in advance for any help, here is what I have so far:

my $Line_QC = "/full/directory/path"; opendir(DIR, "$Line_QC") or die $!; my @files_array = grep { /^35_/ && -f "$Nav_Line_QC/098/$_"} readdir(DIR); my $diag_file = quotemeta"@files_array[0]"; print "@diag_files_array[0]\n"; # prints: 35_Diag_098_a098@421424012017.txt print "$diag_file\n"; # prints: 35_Diag_098_a098\@421424012017\.txt open ( DIAG, "$diag_file" ) ||die ("Failed: $!"); while (my $line = <DIAG>) { if ($line =~ /Line/) { print "$line\n"; }; }; # Close while loop close ( DIAG );

Running this gives me the error: No such file or directory at perlTest line 60.

Replies are listed 'Best First'.
Re: Dealing with files that contain '@' in the filename
by choroba (Cardinal) on Jan 30, 2017 at 10:25 UTC
    It works for me:

    #!/usr/bin/perl use strict; use warnings; my $filename = 'a@b'; open my $out, '>', $filename or die $!; print {$out} 'Contents'; close $out or die $!; opendir my $dir, '.' or die $!; my @files = grep /@/, readdir $dir; die 'Not found' unless grep $filename eq $_, @files; print "Found\n"; unlink $filename;

    I had to create a new script, as yours isn't runnable as is. See SSCCE for details - what's $Nav_Line_QC ? Do you know that $array[0] and @array[0] aren't the same thing? What line is the line 60? The script seems to only have 26 lines.

    ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,
Re: Dealing with files that contain '@' in the filename
by Eily (Monsignor) on Jan 30, 2017 at 10:28 UTC

    You read the files from the folder $Line_QC, and check that they exist in "$Nav_Line_QC/098/", but try to open them in the current directory.

    Also for your information, the $ sigil should be used whenever you fetch a single (scalar) value from a variable. Either the variable already is a scalar, like $diag_file, or you are trying to fetch a single element out of an array (or hash): $diag_files_array[0]. Perl will actually complain about this if you have use warnings; at the top of your program (you should, it lets perl try to guess when you have done something wrong, and perl is often right).

    The quotemeta is not required here, instead if you want to be sure that perl interprets your path correctly, you should use the three parameters version of open,

    my $file; open($file, '<', $path) or die "Can't open file $path: $!"; while (my $line = <$file>) { ... } close($file);
    The '<' parameter tells perl that you are trying to open the file for reading, and so it doesn't need to guess depending on what is inside the variable $path.

    For the filehandle, using a lexical (a my variable) instead of bareword (DIAG in your case) protects your file against being used in the wrong place (DIAG can be used anywhere), and the file would actually be closed automatically when the variable goes out of scope (at the end of the block).

    Last advice, instead of writing die after each open, you can just add use autodie; at the top of your file, to get a useful error message without having to write it yourself.

    Edit: fixed the grammar a little

Re: Dealing with files that contain '@' in the filename
by huck (Prior) on Jan 30, 2017 at 10:35 UTC

    Are you aware that $diag_file has literal backslashes in it?