使用sed和grep / egrep搜索和替换


97

我正在使用egrep -R紧随其后的包含大约10个并集的正则表达式,例如: .jpg | .png | .gifetc。这很好用,现在我想将所有找到的字符串替换为.bmp

我在想类似的东西

egrep -lR "\.jpg|\.png|\.gif" . | sed "s/some_expression/.jpg/" file_it_came_form

因此,这里的问题是如何在其中执行类似的联合正则表达式,sed以及如何告诉它将更改保存到从中获取输入的文件中。


2
我在寻找在目录层次结构中跨多个文件进行搜索和替换的方法时发现了这个问题。对于我这种情况下的其他人,请尝试rpl
titaniumdecoy

谢谢你rpl的作品,真的很容易记住..只是rpl old_string new_string target_files。
cesarpachon 2015年

Answers:


183

使用此命令:

egrep -lRZ "\.jpg|\.png|\.gif" . \
    | xargs -0 -l sed -i -e 's/\.jpg\|\.gif\|\.png/.bmp/g'
  • egrep:使用扩展的正则表达式查找匹配的行

    • -l:仅列出匹配的文件名

    • -R:递归搜索所有给定目录

    • -Z\0用作记录分隔符

    • "\.jpg|\.png|\.gif":匹配字符串之一".jpg"".gif"或者".png"

    • .:在当前目录中开始搜索

  • xargs:以stdin作为参数执行命令

    • -0\0用作记录分隔符。这对于匹配-Zof egrep以及避免被输入文件名中的空格和换行符所迷惑很重要。

    • -l:每个命令使用一行作为参数

  • sed:在小号 tream itor

    • -i:用输出替换输入文件而不进行备份

    • -e:使用以下参数作为表达式

    • 's/\.jpg\|\.gif\|\.png/.bmp/g':替换字符串的所有匹配".jpg"".gif"".png"".bmp"


除了| 在sed部分。我不明白为什么会这样,因为这很有意义... xargs的-l部分给了我错误,所以我将其取出来,这可能相关吗?
Ori

我发现此命令在它处理的所有文件的末尾添加了换行符。
Titandecoy

@titanumdecoy:我无法重现此行为。您使用的是哪个版本的sed,以及您在哪个操作系统上?
David Schmitt,

1
@DavidSchmitt:您可能想将其sed -r用于扩展正则表达式。届时,该模式将与egrep中使用的模式匹配,您可能需要将其放入变量中以供重用。
bukzor 2012年

此命令为我制作的库节省了数小时的工作,将头文件从我的应用程序中复制出来。这很棒:)这是我使用的命令egrep -lRZ“ \ .h $”。| xargs -0 tar -cvf headers.tar | (cp headers.tar headers; cd headers; tar xf headers.tar;)
The Lazy Coder

11

老实说,就像我喜欢为完成适当的任务而完成的工作一样,这绝对是perl的任务-对于这种单行代码,它确实更强大,尤其是“将其写回到其来源”(perl的-i开关可以完成此任务)您,并且还可以选择保留旧版本,例如,附加.bak,只需改用-i.bak

perl -i.bak -pe 's/\.jpg|\.png|\.gif/.jpg/

而不是在sed(甚至可能的话)或awk中进行复杂的工作...


6
sed与perl一样使用-i。
Stobor

@Stobor-我发誓我遇到问题,即使我给了regex选项,输入regex替换字符串时的perl操作也完全符合我的要求,即使我给regex选项sed..我想我要么忘记了一些sed标志,要么它有局限性。
meder omuraliev 2012年

10

另一种方式

find . -name *.xml -exec sed -i "s/4.6.0-SNAPSHOT/5.0.0-SNAPSHOT/" {} \;

有关上述命令的一些帮助

查找将在由指示的当前目录上为您执行查找 .

-name 在我的情况下,文件名pom.xml可以使用通配符。

-exec 执行

sed 流编辑器

-i 忽略大小写

s 替代

/4.6.0.../ 要搜索的字符串

/5.0.0.../ 要替换的字符串


也许没有它那么强大-但这比我接受的答案更容易理解
icc97 '16

5

我无法获得此页面上的任何命令对我有用sed解决方案在它处理的所有文件的末尾添加了换行符,并且perl解决方案无法接受来自find的足够参数。我发现此解决方案非常有效:

find . -type f -name '*.[hm]' -print0 
    | xargs -0 perl -pi -e 's/search_regex/replacement_string/g'

这将递归下降的当前目录树并替换search_regexreplacement_string任何文件结尾.h.m

过去,我也曾将rpl用于此目的。


0

尝试使用for循环

 for i in `egrep -lR "YOURSEARCH" .` ; do echo  $i; sed 's/f/k/' <$i >/tmp/`basename $i`; mv /tmp/`basename $i` $i; done

不漂亮,但是应该做。


3
xargs在这里绝对更合适。
内森·费尔曼

1
并使用该|while read i模式将启用流传输,并在egrep的结果变得太长时避免长度限制
David Schmitt 2010年

0

我的用例是我想替换为 foo:/Drive_Letterfoo:/bar/baz/xyz 我的情况,我可以使用以下代码来实现。我在有大量文件的相同目录位置。

find . -name "*.library" -print0 | xargs -0 sed -i '' -e 's/foo:\/Drive_Letter:/foo:\/bar\/baz\/xyz/g'

希望能有所帮助。

更新s | foo:/ Drive_letter:| foo:/ ba / baz / xyz | g


您可以对sed命令使用其他定界符,这样做会使路径名更加美观:sed 's|foo:/Drive_letter:|foo:/ba/baz/xyz|g'
凯文
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.