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

I got stock on this problem. I am trying to move emails from new to cur folder, I check the content of directory first and after that try to move it:

#!/usr/bin/perl use strict; use warnings; my $newDir = "/home/iphone/Maildir/new"; my $curDir = "/home/iphone/MailDir/cur"; opendir(DIR, "$newDir"); my @FILES= readdir(DIR); closedir DIR; foreach (@FILES) { my $newFile="$currentDir"."\/".$file; my $curFile="$oldDir"."\/".$file; rename $newFile, $curFile; }
Well it does not work and I think the reason is the name of the file with periods, comas etc like: 1340717641.M913153P29268.krasowski,S=3001,W=3072:2,S. Any idea how to solve this ?? Thanks like always Robert

Replies are listed 'Best First'.
Re: Usig file name without backslash escape
by Kenosis (Priest) on Jun 28, 2012 at 02:31 UTC

    Since you're not filtering the directory read, you may be getting more than just files in your @FILES array. Also, you can use the module File::Copy to actually do the file moving for you. Given this, consider the following (untested):

    #!/usr/bin/perl use strict; use warnings; use File::Copy; my $newDir = '/home/iphone/Maildir/new'; my $curDir = '/home/iphone/MailDir/cur'; opendir my $dir, $newDir or die $!; my @FILES = grep { !/^\./ and -f "$newDir/$_" } readdir($dir); closedir $dir; move( "$newDir/$_", "$curDir/$_" ) for @FILES;

    Of course, try it on a scratch directory with sample files before using it on your emails.

    Hope this helps!

      Hmm , rename works with different file, if I create file with simple name like test1.txt I can move it with no trouble, so that function should works with on my system. I tried File::Copy with no luck, will try tomorrow, after I read some more about this. Thanks Robert
Re: Usig file name without backslash escape
by jwkrahn (Abbot) on Jun 28, 2012 at 01:15 UTC
    foreach (@FILES) { my $newFile="$currentDir"."\/".$file; my $curFile="$oldDir"."\/".$file;

    That should be:

    foreach my $file (@FILES) { my $newFile = $curDir."/".$file; my $curFile = $newDir."/".$file;
      Ups, sorry I did not check the code before sending a question. This is corrected code:
      #!/usr/bin/perl use strict; use warnings; my $newDir = "/home/iphone/Maildir/new"; my $curDir = "/home/iphone/MailDir/cur"; my $file; opendir(DIR, "$newDir"); my @FILES= readdir(DIR); closedir DIR; foreach (@FILES) { $file = $_; my $newFile=$newDir."\/".$file; my $curFile=$curDir."\/".$file; print "$newFile\n"; print "$curFile\n"; rename $newFile, $curFile; }
      Response that I am getting is this: /home/iphone/Maildir/new/. /home/iphone/MailDir/cur/. /home/iphone/Maildir/new/1340841279.M908367P21767.krasowski,S=2294,W=2338 /home/iphone/MailDir/cur/1340841279.M908367P21767.krasowski,S=2294,W=2338 /home/iphone/Maildir/new/.. /home/iphone/MailDir/cur/.. /home/iphone/Maildir/new/1340841583.M454288P21927.krasowski,S=2339,W=2384 /home/iphone/MailDir/cur/1340841583.M454288P21927.krasowski,S=2339,W=2384 But no file is moved. Hmm, Any idea what is th problem? Why I can not move these files?? Thanks Robert

        Have you tried asking Perl what the problem is?

        rename $newFile, $curFile or die $!;

        Aaron B.
        Available for small or large Perl jobs; see my home node.

        From rename in perldoc:

        Behavior of this function varies wildly depending on your system implementation. For example, it will usually not work across file system boundaries, even though the system mv command sometimes compensates for this. Other restrictions include whether it works on directories [...]
        For a platform independent move function look at the File::Copy module.

        — which is why you should prefer the solution given by Kenosis, below.

        Athanasius <°(((><contra mundum

Re: Usig file name without backslash escape
by zachhilbert (Initiate) on Jun 28, 2012 at 08:55 UTC
    I was able to get the script to work using filenames similar to yours by this adding 2 lines after $file = $_:

    $file =~ s/\=/\=g;
    $file =~ s/\,/\,/g;

    This just catches the '=' and ',' in the first half, and replaces those with '\=' and '\,' respectively. I had a similar issue as yours in the past and this is how I addressed it. You may also run into '.' and '..' erroring out, but the other files should move. I would also add rename ... or die syntax as was suggested by Aaron.

    Hope this helps.

      In a regex or double-quoteish string, a  \ (backslash) escaped = or , is no different than the unescaped character.

      >perl -wMstrict -le "my $file = 'a=b,c=d,e'; $file =~ s/\=/\=/g; $file =~ s/\,/\,/g; print qq{unchanged: '$file'}; " unchanged: 'a=b,c=d,e'
        I got it working that way:
        <code> #!/usr/bin/perl use strict; use warnings; my $file; opendir(DIR, "$newDir"); my @FILES= readdir(DIR); closedir DIR; foreach (@FILES) { $file = $_; if ($file ne "..") { if ($file ne ".") { my $newFile = "/home/iphone/Maildir/ne +w/$file"; my $curFile = "/home/iphone/Maildir/cu +r/$file"; rename $newFile, $curFile or die $!; } } }
        </code> Thanks for help Robert