调试用于重命名文件的Perl单行命令

4
我正在测试/尝试 this Perl one-liner,并且我正在努力弄清楚文件发生了什么事。我不再看到这些文件了。是我删除了它们还是出了什么问题?
列出的文件名示例(原始):
IMG_0178.JPG
IMG_0182.JPG
IMG_0183.JPG
IMG_0184.JPG
IMG_0186.JPG

我想简单地将文件扩展名改为小写(.jpg):

perl -e'while(<*.JPG>) { s/JPG$/jpg/; rename <*.jpg>, $_ }'
2个回答

9

不要使用 rename 和通配符一起使用。使用标量变量。在替换之前尝试将文件名分配给新变量,并将旧名称重命名为修改后的名称,像这样:

perl -e'while(<*.JPG>) { ($new = $_) =~ s/JPG$/jpg/; rename $_, $new }'

使用 ls -1 检查输出:

IMG_0178.jpg                                                                                                     
IMG_0182.jpg                                                                                                
IMG_0183.jpg                                                                                              
IMG_0184.jpg                                                                                               
IMG_0186.jpg

谢谢。那么我使用的通配符是 rename <*.jpg>?在我的例子中,文件被删除了吗?再次感谢。 - cjd143SD
@cjd143SD:你的命令在我的测试中没有删除任何东西。它保留了同名文件,但我猜<*.jpg>没有匹配到任何内容。我尝试使用<*.JPG>代替,它可以工作,但正如我之前告诉过你的,我更喜欢使用标量的rename命令。 - Birei

4

奇怪的是,你的代码应该做你想要的事情。

在标量上下文中像<*.JPG>这样的文件通配符将返回与模式匹配的下一个文件,由于whilerename都适用于标量上下文,所以这两个文件通配符在每次迭代时返回相同的值。

while (<*.JPG>) {
    s/JPG$/jpg/;
    rename <*.jpg>, $_;
}

循环的第一次迭代中,while会将$_设置为IMG_0178.JPG,替换操作将文件类型设置为小写。

然后在重命名时,<*.jpg>以标量上下文执行,并再次返回IMG_0178.JPG - 在同一列表中的第一个文件,因为Windows文件名不区分大小写。

所以最后的重命名操作执行了rename 'IMG_0178.JPG', 'IMG_0178.jpg',符合要求。

rename重写成这样可以清楚地显示这一点:

sub ren($$) {
  print "$_[0] -> $_[1]\n";
}

while (my $file = <*.JPG>) {
  $file =~ s/JPG$/jpg/;
  ren <*.JPG>, $file;
}

输出

IMG_0178.JPG -> IMG_0178.jpg
IMG_0182.JPG -> IMG_0182.jpg
IMG_0183.JPG -> IMG_0183.jpg
IMG_0184.JPG -> IMG_0184.jpg
IMG_0186.JPG -> IMG_0186.jpg

所以您很幸运,您的文件应该已按您想要的方式重命名了。

但是不要这样做。特别是,应该在任何关键操作的位置使用打印语句来运行程序,以便您可以看到即将发生的情况。

这样做会更好,因为id更清楚地表达了意图。

perl -e '($f = $_) =~ s/JPG$/jpg/i and rename $_, $f while <*.JPG>'

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接