Can't replace word in given contents of Sed / Python / Perl folder
I have a project in which I have folders, subfolders and files. I need to replace Masi with Bond in every file.
I am running the following Sed script which is called unsuccessful replacement
s/Masi/Bond/
in Zsh on
sed -f PATH/replace PATH2/project/**
It gives me all the files as well as the ones that don't have Masi as output.
Sed is not necessarily the best tool for the task. I'm interested in Python and Perl.
How do I perform a substitution in Sed / Perl / Python to only change the contents of a file?
a source to share
To replace a 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 the filenames. Safer:
find . -type f -exec perl -p -i -e 's/Masi/Bond/g' {} \;
or on a Mac that has spaces in filenames
find . -type f -print0 | xargs -0 perl -p -i -e 's/Masi/Bond/g'
Clarifications
- -p means seal or stamp
- -i means "do not create backup files"
- -e allows you to run perl code on the command line
a source to share
Why not just pass the -i
( man sed
) parameter to sed and be done with it? If it doesn't find Masi in the file, the file will simply be overwritten without any changes. Or am I missing something?
If you don't want to replace the content of the inline file (which is what it will do -i
), you can do what you are now, but throw in front of it grep
andxargs
grep -rl Masi PATH/project/* | xargs sed -f PATH/replace
Lots of options, but don't write an entire perl script to do this (I'll give a one line pass;)). find
, grep
, sed
, xargs
, Etc. will always be more flexible, IMHO.
In response to a comment:
grep -rl Masi PATH/project/* | xargs sed -n -e '/Masi/ p'
a source to share
Rename file folder:
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 );
}
}
- strict (core) - Perl pragma to restrict unsafe constructs
- warnings (kernel) - Perl pragma to manage additional warnings
- File :: Find :: Rule - Alternative interface to file :: Find
- File :: Find (core) - Traverse the directory tree.
- File :: Slurp - Efficiently read / write full files
- File :: Copy (core) - copy files or file descriptors
a source to share
Solution tested on Windows
Requires CPAN Module File :: Slurp. Will work with standard Unix shell templates. How. /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";
}
}
}
a source to share