轻松替换多个文件中的 with/without 正则表达式
Easy replace with/without regex in multiple files
我每天有数百次需要在文件中搜索模式,有时我不得不用其他东西替换这些模式。大多数时候它是简单的模式,比如一个词或一个短句,但有时我不得不寻找更复杂的正则表达式。我不太喜欢 sed
(至少我的 sed
版本是这样,因为它不太符合 PCRE 引擎)。所以我更喜欢使用 perl -pi -e
。
但是,由于强制性的 -i.bak 临时文件,Perl pie 在 Cygwin 上并不是很有吸引力。我需要找到一种方法在处理后自动删除 .bak 文件。此外,如果我想在项目中递归替换,我必须先列出所有文件:
find . | xargs -n1 perl -pi -e 's/foo/bar/'
这个命令写起来很长,特别是如果你一个月使用它一千次的话。所以我决定编写一个更有用的工具,其工作方式与伟大的白银搜索器 ag
相同。
ag 'foo\d{3}[^\w]' # Search for a pattern
# Oh yes this one should be renamed!
replace 's/(foo)\d{3}[^\w]/\U\E_bar/g'
我写了这个很原始的bash函数
function replace
{
EXTENSION=.perlpie_tmp
perl -p -i$EXTENSION -e ${*:2}
for file in ${*:2}; do
rm "$file$EXTENSION";
done;
}
但我一点都不满意,因为如果参数不超过一个,它不会自动递归搜索所有文件。如果参数的数量是 1
,我可以修改这个函数并添加 find .
,或者我可以用 Perl 编写一个非常复杂的程序,它可以支持命令行选项、漂亮的输出、智能案例搜索甚至纯文本搜索。
这个问题最合适的选择是什么?linux 世界上是否有任何高级 search/replace 工具?如果没有,我可能会尝试编写自己的 rip
工具来代表 replace-in-place
,它可以支持我需要的所有选项。
在此之前我需要一些建议...
编辑
实际上我想分叉 https://github.com/petdance/ack2 以添加替换功能...这可能是个好主意也可能不是...
这是您函数的替代方法(已编辑为使用 the suggestion provided by gniourf_gniourf,谢谢):
find -type f . -exec sh -c 'perl -pi.bak -e "s/foo/bar/" "[=10=]" && rm -f "[=10=]".bak' {} \;
使用这种方法,您可以随时删除文件。
我觉得你可以用
grep -Hrn -e "string" .
寻找规律,
find -type f -exec sed -i "s@string1@string2@g" {} \;
替换模式
我会稍微修改一下您现有的功能:
function replace {
local perl_code= EXTENSION=.perlpie_tmp file
shift
for file; do
perl -p -i$EXTENSION -e "$perl_code" "$file" && rm "$file$EXTENSION"
done;
}
这会稍微降低性能,因为您现在多次调用 perl,但我怀疑您不会注意到。
我每天有数百次需要在文件中搜索模式,有时我不得不用其他东西替换这些模式。大多数时候它是简单的模式,比如一个词或一个短句,但有时我不得不寻找更复杂的正则表达式。我不太喜欢 sed
(至少我的 sed
版本是这样,因为它不太符合 PCRE 引擎)。所以我更喜欢使用 perl -pi -e
。
但是,由于强制性的 -i.bak 临时文件,Perl pie 在 Cygwin 上并不是很有吸引力。我需要找到一种方法在处理后自动删除 .bak 文件。此外,如果我想在项目中递归替换,我必须先列出所有文件:
find . | xargs -n1 perl -pi -e 's/foo/bar/'
这个命令写起来很长,特别是如果你一个月使用它一千次的话。所以我决定编写一个更有用的工具,其工作方式与伟大的白银搜索器 ag
相同。
ag 'foo\d{3}[^\w]' # Search for a pattern
# Oh yes this one should be renamed!
replace 's/(foo)\d{3}[^\w]/\U\E_bar/g'
我写了这个很原始的bash函数
function replace
{
EXTENSION=.perlpie_tmp
perl -p -i$EXTENSION -e ${*:2}
for file in ${*:2}; do
rm "$file$EXTENSION";
done;
}
但我一点都不满意,因为如果参数不超过一个,它不会自动递归搜索所有文件。如果参数的数量是 1
,我可以修改这个函数并添加 find .
,或者我可以用 Perl 编写一个非常复杂的程序,它可以支持命令行选项、漂亮的输出、智能案例搜索甚至纯文本搜索。
这个问题最合适的选择是什么?linux 世界上是否有任何高级 search/replace 工具?如果没有,我可能会尝试编写自己的 rip
工具来代表 replace-in-place
,它可以支持我需要的所有选项。
在此之前我需要一些建议...
编辑
实际上我想分叉 https://github.com/petdance/ack2 以添加替换功能...这可能是个好主意也可能不是...
这是您函数的替代方法(已编辑为使用 the suggestion provided by gniourf_gniourf,谢谢):
find -type f . -exec sh -c 'perl -pi.bak -e "s/foo/bar/" "[=10=]" && rm -f "[=10=]".bak' {} \;
使用这种方法,您可以随时删除文件。
我觉得你可以用
grep -Hrn -e "string" .
寻找规律,
find -type f -exec sed -i "s@string1@string2@g" {} \;
替换模式
我会稍微修改一下您现有的功能:
function replace {
local perl_code= EXTENSION=.perlpie_tmp file
shift
for file; do
perl -p -i$EXTENSION -e "$perl_code" "$file" && rm "$file$EXTENSION"
done;
}
这会稍微降低性能,因为您现在多次调用 perl,但我怀疑您不会注意到。