【问题标题】:Unable to replace the word in a given folder's contents by Sed/Python/Perl无法用 Sed/Python/Perl 替换给定文件夹内容中的单词
【发布时间】:2010-10-28 01:04:58
【问题描述】:

我有一个项目,其中有文件夹、子文件夹和文件。我需要在每个文件中用单词 Bond 替换 Masi。

我运行以下名为 replace 的 Sed 脚本失败

s/Masi/Bond/

在 Zsh 中由

sed -f PATH/replace PATH2/project/**

它给了我所有文件,包括那些没有 Masi 的文件,作为输出。

Sed 不一定是完成任务的最佳工具。 我对 Python 和 Perl 很感兴趣。

您将如何在 Sed/Perl/Python 中进行替换,以便仅更改文件内容?

【问题讨论】:

  • 要替换文件名中的字符串还是文件内容中的字符串?
  • 是什么让您认为 sed 可以重命名目录?为什么不使用“mv”或其他重命名文件的命令?
  • @fmarc:我想替换文件内容中的字符串,而不是文件名中的字符串。
  • 如果您选择 sed 路线,您可能希望 s/Masi/Bond/g(注意 g)替换所有 Masi 实例,而不仅仅是一行中的第一个。

标签: python perl sed replace


【解决方案1】:

替换当前目录和子目录中所有文件中的单词

perl -p -i -e 's/Masi/Bond/g' $(grep -rl Masi *)

如果文件名中有空格,上述方法将不起作用。更安全:

find . -type f -exec perl -p -i -e 's/Masi/Bond/g' {} \;

或在文件名中有空格的 Mac 中

find . -type f -print0 | xargs -0 perl -p -i -e 's/Masi/Bond/g'

说明

  • -p 表示打印或死亡
  • -i 表示“不做任何备份文件”
  • -e 允许你在命令行中运行 perl 代码

【讨论】:

  • +1 获得出色的 grep 技巧,仅修改需要更改的文件。
  • +1 你打败了我。这是我最喜欢的 perl one 班轮。问题是:在使用这一行在几秒钟内修复了数百个文件之后,您是继续工作,还是因为使用记事本的人需要多长时间,所以您会继续工作吗?
  • -i 表示大小写无关紧要。 -p 和 -e 的其他选项是什么?我没有在 man perl 中找到对它们的解释。
  • @Masi:不; -i 表示没有备份文件的就地更改。例如,您可以使用“-i.bak”让 Perl 为每个修改的文件创建一个 filename.bak 备份文件。
  • @Masi:尝试使用 'man perlrun' 而不是 'man perl' 以获取有关 p、i 和 e 标志的详细信息:perldoc.perl.org/perlrun.html
【解决方案2】:
import glob
import os

# Change the glob for different filename matching 
for filename in glob.glob("*"):
  dst=filename.replace("Masi","Bond")
  os.rename(filename, dst)

【讨论】:

    【解决方案3】:

    为什么不直接将 -i 选项 (man sed) 传递给 sed 并完成它?如果它没有在文件中找到 Masi,则文件将被重写而不进行任何修改。还是我错过了什么?

    如果您不想替换内联文件的内容(-i 将执行此操作),您可以像现在一样执行此操作,但在其前面添加 grepxargs

    grep -rl Masi PATH/project/* | xargs sed -f PATH/replace
    

    有很多选项,但不要为此编写一个完整的 perl 脚本(我会给单行代码一个通过;))。 findgrepsedxargs 等将永远更加灵活,恕我直言。

    回应评论:

    grep -rl Masi PATH/project/* | xargs sed -n -e '/Masi/ p'
    

    【讨论】:

    • @Sean:如何在运行命令之前查看哪些行将被更改?
    • @Sean:您的解决方案在关键环境中是否安全,类似于stackoverflow.com/questions/894802/… ?我不确定组合这些命令有多安全。
    【解决方案4】:

    在 Windows 上测试的解决方案

    需要 CPAN 模块 File::Slurp。将使用标准的 Unix shell 通配符。比如 ./replace.pl PATH/replace.txt PATH2/replace*

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    use File::Glob ':glob';
    use File::Slurp;
    foreach my $dir (@ARGV) {
      my @filelist = bsd_glob($dir);
      foreach my $file (@filelist) {
        next if -d $file;
        my $c=read_file($file);
        if ($c=~s/Masi/Bond/g) {
          print "replaced in $file\n";
          write_file($file,$c);
        } else {
          print "no match in $file\n";
        }
      }
    }
    

    【讨论】:

    • shell 通配符将由 shell 处理。在 Perl 中处理它们是不必要的。
    • 取决于操作系统 :) - 我正在 Windows 上进行测试。
    • 我和亚历山大在这里。我从未见过 Windows shell 进行通配符扩展。
    【解决方案5】:

    重命名一个充满文件的文件夹:

    use warnings;
    use strict;
    use File::Find::Rule;
    
    my @list = File::Find::Rule->new()->name(qr/Masi/)->file->in('./');
    
    for( @list ){
       my $old = $_;
       my $new = $_;
       $new =~ s/Masi/Bond/g;
       rename $old , $new ;
    }
    

    替换文件中的字符串

    use warnings;
    use strict;
    use File::Find::Rule;
    use File::Slurp;
    use File::Copy;
    
    my @list = File::Find::Rule->new()->name("*.something")->file->grep(qr/Masi/)->in('./');
    
    for( @list ){
       my $c = read_file( $_ );
       if ( $c =~ s/Masi/Bond/g; ){
        File::Copy::copy($_, "$_.bak"); # backup.
        write_file( $_ , $c );
       }
    }
    

    【讨论】:

    • 最后一个脚本是否重命名所有文件,包括子目录? - - Chaos 在lostsouls.org/grimoire_convert_all 给了我他类似的脚本。您的脚本似乎更短。这表明我它不是纯粹的 Perl。您会改进脚本中的哪些部分以使其在关键环境中安全?
    • @Masi ,呃,当然是纯粹的 perl,它只是使用模块来完成繁重的工作,他们完成了所有已经为我解决的艰苦工作。 File::Find::Rule 对于关键环境来说是完全安全的,可能 more 而不是用手动 opendir DIY 的,因为它至少 testedmultiple 平台按预期工作。
    猜你喜欢
    • 2014-03-15
    • 2017-06-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多