如何递归更改名称与 Perl 中的字符串匹配的目录中的文件?

How to recursively change files in directories whose name matches a string in Perl?

我有很多不同项目的目录。在某些项目目录下,有名为"matlab_programs"的子目录。在仅名为 matlab_programs 的子目录中,我想在以 *.m.

结尾的文件中将字符串 'red' 替换为 'blue'

以下 perl 代码将递归替换所有 *.m 文件中的字符串,无论这些文件位于哪个子目录中。

find . -name "*.m" | xargs perl -p -i -e "s/red/blue/g"

并查找名为 matlab_programs、

的所有目录的完整路径
find . -type d -name "matlab_programs"

如果文件位于名为 matlab_programs 的子目录中,我该如何组合它们以便仅替换字符串?

Perl 具有出色的 File::Find 模块,它允许您指定要在每个文件上调用的回调。

因此您可以指定一个复杂的复合条件,如下所示:

#!/usr/bin/env perl

use strict;
use warnings;

use File::Find;

sub find_files {
    next unless m/\.m\z/;    # skip any files that don't end in .m
    if ( $File::Find::dir =~ m/matlab_programs$/ ) {
        print $File::Find::name, " found\n";
    }
}

find( \&find_files, "." );

然后您可以对找到的文件做任何您想做的事情 - 例如 opening/text 替换和关闭。

你有bash吗? $(...) 语法像反引号一样工作(shell 和 Perl 使用它们的方式)但它们可以嵌套。

perl -pi -e s/red/blue/g $(find $(find . -type d -name matlab_programs) -type f -name \*.m)

find 的许多版本也支持 -path pattern 测试,因此您可以将文件名条件组合到该参数中

perl -pi -e s/red/blue/g $(find . -type f -path \*/matlab_programs/\*.m)

您想使用

查找所有名为 matlab_programs 的目录
find . -type d -name "matlab_programs"

然后执行

find $f -name "*.m" | xargs perl -p -i -e "s/red/blue/g"

所有结果 $f。从您使用 xargs 判断,您的文件名中没有空格等特殊字符。所以以下应该有效:

find `find . -type d -name "matlab_programs"` -name "*.m" |
xargs perl -p -i -e "s/red/blue/g"

find . -type d -name "matlab_programs" |
while read f
do
  find $f -name "*.m" | xargs perl -p -i -e "s/red/blue/g"
done |
xargs perl -p -i -e "s/red/blue/g"

顺便说一句,我在这里使用单引号;每当要按字面意思理解引用的字符串时,我总是使用它们。