Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

Why can't I figure this out?????

by JSAWS (Novice)
on Aug 31, 2022 at 11:36 UTC ( [id://11146554]=perlquestion: print w/replies, xml ) Need Help??

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

Hi Monks,

I have been banging my head against the wall for hours with this, I am using this method in multiple places but somehow it does not work here...

Here is the logic:

I comapre 2 files (OldPicList and NewPicList) and if values are found in NewPicList only then the relevant dir should be read and the contents written to a file (filenames only).

All is generally well, except if the filenames have spaces in them....

example the following list will only print the first 7 items to the file

20141025_211155b.jpg
20141028_140739b.jpg
20141101_160837b.jpg
20141101_160839b.jpg
20141101_160856b.jpg
20141102_112335b.jpg
Screenshot_from_2021-02-04_17-38-07.png
Screenshot from 2021-02-04 19-13-44.png
Screenshot from 2021-02-05 08-59-49.png
Screenshot from 2021-02-09 11-48-40.png
Screenshot from 2021-02-09 15-46-23.png
Screenshot from 2021-02-10 09-46-34.png
Screenshot from 2021-02-11 10-06-13.png
Screenshot from 2021-02-15 14-52-40.png

What puzzles me is that when I print the @array to STDOUT before the FH the output is correct and contains all files (the file list above is the printout of the array, there seems to be an extra char at the end of every line, this might be the issue?

completely puzzled..... any help would be greatly appreciated!

J
foreach $a (@NewPicList) { chomp($a); $a =~ s/^\s+//; if (grep(/$a\s+$/, @OldPicList)) { } else { push @NewPicFolders, "$a"; } } foreach $b (@NewPicFolders) { open (RD, "ls -l /dir1/dir2/dir3/'$b' |"); binmode RD, ':encoding(UTF-8)'; while (<RD>) { push @user_dir, $_; } close(RD); s{^\s+|\s+$}{}g foreach @user_dir; foreach $fileline (@user_dir) { @filenames = split(/\s+/,$fileline, 9); unless (@filenames[8] eq "") { $filenames[8] =~ s/\s+/_/g; push @PicList, "$filenames[8]\n"; } } print "PICLIST: @PicList"; open(FH, '>', "/dir1/dir2/dir3/$b.folder") or die $!; print FH "@PicList"; close FH; @PicList = (); @user_dir = (); @filenames = (); }

Replies are listed 'Best First'.
Re: Why can't I figure this out?????
by Corion (Patriarch) on Aug 31, 2022 at 11:40 UTC
    open (RD, "ls -l /dir1/dir2/dir3/'$b' |"); ... foreach $fileline (@user_dir) { @filenames = split(/\s+/,$fileline, 9);

    Consider using opendir and readdir (or even File::Find) there, instead of reading from ls -l. If all else fails, consider using ls -1 at least so you only get a single filename per row, instead of having to parse and split things.

    The following could give you a start:

    my $dir = "/dir1/dir2/dir3/$b"; opendir my $dh, or die "Couldn't read directory '$dir'"; my @user_dir = map { "$dir/$_" } grep { $_ !~ /^\.\.?$/ } readdir $dh; ... foreach my $fileline (@user_dir) { my $filename = $fileline; ... }
      Or just
      foreach my $fileline (<$dir/*>) { }

      since globbing already removes dotfiles and includes the path.

      Personally, I'd use Path::Tiny or Path::Class before touching opendir.

      true... true.... I use this method multiple times.... sometimes I need info from the other fields :)

        Instead of worrying about whitespace in filenames and proper quoting etc. , I can only recommend using readdir for the filename and stat for the other fields.

Re: Why can't I figure this out?????
by hv (Prior) on Aug 31, 2022 at 12:46 UTC

    I suspect the issue here is that your `ls` may be wrapping filenames in quotes if they have a space:

    % ls -l drwxr-xr-x 2 hv hv 4096 Aug 10 2015 Desktop drwxrwxr-x 3 hv hv 4096 Sep 15 2020 'My Games'

    On my system, I can get consistent results by adding "-Q" to the options, to have every filename quoted:

    % ls -l -Q drwxr-xr-x 2 hv hv 4096 Aug 10 2015 "Desktop" drwxrwxr-x 3 hv hv 4096 Sep 15 2020 "My Games"

    More generally, however, `ls` output is designed for humans, I would echo others' suggestions that you should use readdir() and stat() if you want reliable behaviour.

    I'll note that you are also using (partially unanchored) pattern matching to compare the "new" list to the "old" list; that will also likely come to bite you eventually - better to clean up both lists and then do an equality check, which could be done fastest with a hash lookup:

    my %OldFile; for my $file (@OldPicList) { $file =~ s{^\s+|\s+$}{}g; $oldFile{$file} = 1; } my @NewPicFolders; for my $file (@NewPicList) { $file =~ s{^\s+|\s+$}{}g; if ($oldFile{$file}) { # nothing } else { push @NewPicFolders, $file; } }
Re: Why can't I figure this out?????
by JSAWS (Novice) on Aug 31, 2022 at 11:41 UTC
    sorry one correction

    the command filenames[8] =~ s/\s+/_/g; was added to check if replacing whitespaces with _ helped.... it did not.... but if I rename the file without whitespace manually then it gets included in the file.

    J

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others lurking in the Monastery: (2)
As of 2024-04-24 16:24 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found