【问题标题】:How to recursively change files in directories whose name matches a string in Perl?如何递归更改名称与 Perl 中的字符串匹配的目录中的文件?
【发布时间】:2015-07-14 19:45:01
【问题描述】:

我有很多不同项目的目录。在一些项目目录下,有名为“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 的子目录中时替换字符串?

【问题讨论】:

    标签: regex perl find


    【解决方案1】:

    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, "." );
    

    然后你可以对你找到的文件做任何你想做的事情——比如打开/文本替换和关闭。

    【讨论】:

    • 在匹配文件名时使用\z 而不是$ ...除非您明确希望"program.m\n" 匹配。
    • @SinanÜnür:在这种情况下,模式应该是/\.m\n?\z/。很少有人(包括 Linux 用户)知道 Linux 文件名可能包含除 NUL 之外的控制字符
    • 很少有人需要。虽然文件名中确实可能嵌入了很多讨厌的东西,但我们正在谈论在特定目录结构中查找 matlab 文件。假设这些特定文件不存在并非不合理。
    【解决方案2】:

    您想查找所有名为 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"
    

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

    【讨论】:

    • 尽管我的 Perl 背景有限,但这很有效,而且我很容易理解,所以谢谢!
    • 空格(在 matlab_programs 子目录出现的项目目录名称中,而不是文件名中)确实会导致问题。但这仅发生在数百个子目录中的几个子目录中,当它发生时,由于您的评论,我明白发生了什么。
    • 可以修复示例以处理名称中的空格,但这总是很麻烦。如果可以的话,最好事先清理文件名。
    【解决方案3】:

    你有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)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-07-06
      • 2018-10-06
      • 2022-08-17
      • 1970-01-01
      • 1970-01-01
      • 2022-08-19
      • 1970-01-01
      相关资源
      最近更新 更多