[英]Find/Replace in files recursively but touch only files with matches
我想以遞歸方式快速搜索和替換有或沒有正則表達式的文件。 另外,我只需要搜索特定文件,並且我不想觸摸與我的search_pattern不匹配的文件,否則git會認為所有解析的文件都已修改(find。--exec sed會發生這種情況)。
我使用find,grep,sed或ack嘗試了很多在Internet上找到的解決方案,但我認為它們僅匹配特定文件並不是很好。
最終我寫了這個perl腳本:
#!/bin/perl
use strict;
use warnings;
use File::Find;
my $search_pattern = $ARGV[0];
my $replace_pattern = $ARGV[1];
my $file_pattern = $ARGV[2];
my $do_replace = 0;
sub process {
return unless -f;
return unless /(.+)[.](c|h|inc|asm|mac|def|ldf|rst)$/;
open F, $_ or print "couldn't open $_\n" && return;
my $file = $_;
my $i = 0;
while (<F>) {
if (m/($search_pattern)/o) {$i++};
}
close F;
if ($do_replace and $i)
{
printf "found $i occurence(s) of $search_pattern in $file\n";
open F, "+>".$file or print "couldn't open $file\n" && return;
while (<F>)
{
s/($search_pattern)/($replace_pattern)/g;
print F;
}
close F;
}
}
find(\&process, ".");
我的問題是:
下方是否有類似這樣的更好解決方案(不存在)?
`repaint -n/(.+)[.](c|h|inc|asm|mac|def|ldf|rst)$/ s/search/replacement/g .`
附屬問題:
我的perl腳本怎么樣? 還不錯嗎? 我真的需要重新打開每個與search_pattern匹配的文件嗎?
人們如何處理這項瑣碎的任務? 幾乎每個好的文本編輯器都具有“在文件中搜索和替換”功能,但沒有vim。 vim用戶如何做到這一點?
編輯:
我也用ff | xargs perl -pi -e 's/foo/bar/g'
嘗試了這個腳本ff.pl。 ff | xargs perl -pi -e 's/foo/bar/g'
但是它沒有按我預期的那樣工作。 它創建了一個備份.bak,即使在-pi之后我什么也沒給出。 看來這是cygwin中的正常行為,但是我不能真正使用perl -pi -e
#!/bin/perl
use strict;
use warnings;
use File::Find;
use File::Basename;
my $ext = $ARGV[0];
sub process {
return unless -f;
return unless /\.(c|h|inc|asm|mac|def|ldf|rst)$/;
print $File::Find::name."\n" ;
}
find(\&process, ".");
重新編輯:
我終於遇到了這個解決方案(在cygwin下,我需要刪除備份文件)
find . | egrep '\.(c|h|asm|inc)$' | xargs perl -pi.winsucks -e 's/<search>/<replace>/g'
find . | egrep '\.(c|h|asm|inc)\.winsucks$' | xargs rm
不錯,但有幾點注意事項:
s /($ search_pattern)/($ replace_pattern)/ g;
()是不必要的,實際上會干擾$ replace_pattern中的計數器
/(.+)[.](c|h|inc|asm|mac|def|ldf|rst)$/應該寫成
/\\.(c|h|inc|asm|mac|def|ldf|rst)$/也可能是/ i
我真的需要重新打開每個與search_pattern匹配的文件嗎?
我不知道vim,而是使用emacs,它有幾種方法可以完成此操作。
以下命令有什么問題?
:grep foo **/*.{foo,bar,baz}
:cw
它不會對任何VCS造成任何問題,並且是非常基本的Vimming。
沒錯,Vim沒有專門的“在文件中搜索和替換”功能,但是有一些插件 。
為什么不只是:
grep 'pat' -rl *|xargs sed -i 's/pat/rep/g'
還是我不明白Q對嗎?
以下是代碼的清理版本。
use strict;
並在每個perl腳本的頂部use warnings
。 如果您正在執行文件處理,請包括use autodie;
也一樣 File::Find::Rule
。 使用File::Find
有效,在這種情況下,實際上可能是首選的模塊,但是我喜歡后者的接口。 和代碼:
use strict;
use warnings;
use autodie;
use File::Find;
my $search_pattern = $ARGV[0];
my $replace_pattern = $ARGV[1];
my $file_pattern = $ARGV[2];
my $do_replace = 0;
sub process {
return if !-f;
return if !/[.](?:c|h|inc|asm|mac|def|ldf|rst)$/;
my $data = do {
open my $fh, '<', $_;
local $/;
<$fh>;
};
my $count = $data =~ s/$search_pattern/$replace_pattern/g
or return;
print "found $count occurence(s) of $search_pattern in $_\n";
return if !$do_replace;
open my $fh, '>', $_;
print $fh $data;
close $fh;
}
find(\&process, ".");
我建議使用find2perl
如果它不能立即使用,您可以調整它生成的代碼:
find2perl /tmp \! -name ".*?\.(c|h|inc|asm|mac|def|ldf|rst)$" -exec "sed -e s/aaa/bbb/g {}"
它將以下代碼輸出到stdout:
#! /usr/bin/perl -w
eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
if 0; #$running_under_some_shell
use strict;
use File::Find ();
# Set the variable $File::Find::dont_use_nlink if you're using AFS,
# since AFS cheats.
# for the convenience of &wanted calls, including -eval statements:
use vars qw/*name *dir *prune/;
*name = *File::Find::name;
*dir = *File::Find::dir;
*prune = *File::Find::prune;
sub wanted;
sub doexec ($@);
use Cwd ();
my $cwd = Cwd::cwd();
# Traverse desired filesystems
File::Find::find({wanted => \&wanted}, '/tmp');
exit;
sub wanted {
my ($dev,$ino,$mode,$nlink,$uid,$gid);
(($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) &&
! /^\..*.?\\.\(c|h|inc|asm|mac|def|ldf|rst\)\$\z/s &&
doexec(0, 'sed -e s/aaa/bbb/g {}');
}
sub doexec ($@) {
my $ok = shift;
my @command = @_; # copy so we don't try to s/// aliases to constants
for my $word (@command)
{ $word =~ s#{}#$name#g }
if ($ok) {
my $old = select(STDOUT);
$| = 1;
print "@command";
select($old);
return 0 unless <STDIN> =~ /^y/;
}
chdir $cwd; #sigh
system @command;
chdir $File::Find::dir;
return !$?;
}
如果要執行,可以將其通過管道傳遞給perl:
find2perl /tmp \! -name ".*?\.(c|h|inc|asm|mac|def|ldf|rst)$" -exec "sed -e s/aaa/bbb/g" | perl
您可以嘗試使用Vim的此插件: https : //github.com/skwp/greplace.vim
基本上,它允許您鍵入搜索階段(使用/不使用正則表達式),並詢問您要搜索的文件。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.