简体   繁体   English

无法用Sed / Python / Perl替换给定文件夹内容中的单词

[英]Unable to replace the word in a given folder's contents by Sed/Python/Perl

I have a project where I have folders, subfolders, and files. 我有一个项目,其中有文件夹,子文件夹和文件。 I need to replace the word Masi by the word Bond in each files. 我需要在每个文件中用“邦迪”一词代替“马西”一词。

I run the following Sed script called replace unsuccessfully 我运行以下名为替换的Sed脚本失败

s/Masi/Bond/

in Zsh by 在Zsh中

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

It gives me all files, also the ones which do not have Masi, as an output. 它为我提供了所有文件,也包括没有Masi的文件作为输出。

Sed is not necessarily the best tool for the task. Sed不一定是完成任务的最佳工具。 I am interested in Python and Perl. 我对Python和Perl感兴趣。

How would you do the replacement in Sed/Perl/Python, such that only the file contents are changed? 您将如何在Sed / Perl / Python中进行替换,以便仅更改文件内容?

To replace the word in all files found in the current directory and subdirectories 替换当前目录和子目录中所有文件中的单词

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

The above won't work if you have spaces in filenames. 如果文件名中有空格,则上述方法将无效。 Safer to do: 做得更安全:

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

or in Mac which has spaces in filenames 或在Mac(文件名中包含空格)

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

Explanations 说明

  • -p means print or die -p表示打印或死
  • -i means "do not make any backup files" -i表示“不制作任何备份文件”
  • -e allows you to run perl code in command line -e允许您在命令行中运行perl代码

Why not just pass the -i option ( man sed ) to sed and be done with it? 为什么不只将-i选项( man sed )传递给sed并完成它呢? If it doesn't find Masi in a file, the file will just be rewritten with no modification. 如果未在文件中找到Masi,则将对该文件进行修改,而无需进行任何修改。 Or am I missing something? 还是我错过了什么?

If you don't want to replace the files' contents inline (which is what the -i will do) you can do exactly as you are now, but throw a grep & xargs in front of it: 如果您不想内联替换文件内容(这是-i会做的事情),则可以像现在一样完全进行操作,但是在其前面加上grepxargs

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

Lots of options, but do not write an entire perl script for this (I'll give the one-liner a pass ;)). 选项很多,但不要写这个整个perl脚本(我给了一个班轮合格;))。 find , grep , sed , xargs , etc. will always be more flexible, IMHO. 恕我直言, findgrepsedxargs等将总是更加灵活。

In response to comment: 回应评论:

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

Renaming a folder full of files: 重命名充满文件的文件夹:

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 ;
}

Replacing Strings in Files 替换文件中的字符串

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 );
   }
}

A solution tested on Windows 在Windows上测试过的解决方案

Requires CPAN module File::Slurp. 需要CPAN模块File :: Slurp。 Will work with standard Unix shell wildcards. 将与标准Unix shell通配符一起使用。 Like ./replace.pl PATH/replace.txt PATH2/replace* 像./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";
    }
  }
}
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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM