使用基于模式文件的grep + sed?

时间:2016-03-27 13:49:46

标签: regex sed grep

问题在于:我有~35k个文件,可能包含或不包含300行中包含正则表达式的列表中的一个或多个字符串

如果我grep -rnwl 'C:\out\' --include=*.txt -E --file='comp.log'我看到有几千个包含匹配项的文件。

现在我如何获取sed删除这些包含以前使用的comp.log中的字符串的文件中的每一行?

edit:comp.log在每一行中都包含一个简单的正则表达式,但大多数情况下每个要匹配的字符串都是唯一的

这是一个如何构建的例子:

server[0-9]\/files\/bobba fett.stw
[a-z]+ mochaccino
[2-9] CheeseCakes
...

等。除了愚蠢的例子,它表明每一行都是独一无二的,除了一些变化,所以它不应该影响我真正想要的东西:看看这些行中的任何一行是否与正在处理的文件中的行匹配。它没有什么不同于&pattern / replacement /'除了我想使用文件中的模式而不是内联。

好的,这是一个更新(如果我几天之后没有回答问题,那么S.O.会住院病人) 在摆弄@ Kenavoz / @Fischer方法之后,我找到了一个完全不同的解决方案,但首先要做的事情。 为sed创建一个修改后的模式列表,以便完成工作。

以及@ werkritter完全放弃sed的方法。 (这个我发现最多......错误......"最不容易解决问题的方法)。

我无法在Windows / cygwin下使@Mklement的答案工作(它确实在ubuntu下工作,所以...不确定这意味着什么。数字。)

最终以一种更长期,可重复使用的形式解决问题的方法是一个名为PowerGrep的大学指出的精彩节目。它确实将所有其他选项从水中吹走。不幸的是它只是窗户并且它不是免费的。 (甚至不在这里做广告,事情并不便宜,但它确实解决了问题)。

所以考虑到@ werkiter的回复不是"正确的"回答,我不能只选择@Lars Fischer和@ Kenavoz的答案作为解决方案(它们相互补充),我正在授予@Kenavoz作为第一个的标记。

最后的想法:我希望有一个更简单,通用和免费的解决方案,但显然没有。

3 个答案:

答案 0 :(得分:2)

你可以试试这个:

sed -f <(sed 's/^/\//g;s/$/\/d/g' comp.log) file > outputfile

comp.log中的所有正则表达式都使用d命令格式化为sed地址:/regex/d。此命令删除与模式匹配的行。

此内部sed作为文件(process substitition)发送到应用于-f的外部sed的file选项。

仅删除匹配模式的字符串(不是所有行):

sed -f <(sed 's/^/s\//g;s/$/\/\/g/g' comp.log) file > outputfile

更新:

命令输出重定向到outputfile

答案 1 :(得分:2)

一些想法,但不是一个完整的解决方案,因为它需要一些采用你的脚本(未在问题中显示)。

  1. 我会将comp.log转换为包含必要删除的sed脚本:

    cat comp.log | sed -r "s+(.*)+/\1/ d;+" > comp.sed`
    

    这会让你的例子看起来像:

    /server[0-9]\/files\/bobba fett.stw/ d;
    /[a-z]+ mochaccino/ d;
    /[2-9] CheeseCakes/ d;
    
  2. 然后我将comp.sed脚本应用于grep报告的每个文件(使用-rnwl需要一些过滤来获取文件名。):

    sed -i.bak -f comp.sed $AFileReportedByGrep
    

    如果你有gnu sed,你可以使用-i inplace replacement创建.bak备份,否则使用管道到临时文件

答案 2 :(得分:0)

Kenavoz's answerLars Fischer's answer都使用相同的巧妙方法:
将输入正则表达式列表转换为sed匹配和删除命令列表,通过sed作为脚本传递给-f

使用单个命令来补充这些答案,假设您有 GNU sed并且您的shell是bashksh或者zsh(支持<(...)):

find 'c:/out' -name '*.txt' -exec sed -i -r -f <(sed 's#.*#/\\<&\\>/d#' comp.log) {} +
  • find 'c:/out' -name '*.txt'匹配dir子树中的所有*.txt个文件。 c:/out

    • -exec ... +传递的匹配文件数量与指定命令的单个命令行相同,通常只会导致单个调用。
  • sed -i更新输入文件就地(从概念上讲 - 有警告);附加后缀(例如-i.bak)以保存带有该后缀的原始文件的备份。

  • sed -r激活对扩展正则表达式的支持,这是输入正则表达式。

  • sed -f从指定的文件名中读取要执行的脚本,在这种情况下,如Kenavoz's answer中所述,使用进程替换(<(...))来封闭sed命令的输出就像一个[瞬态]文件。

    • s/// sed命令 - 使用替代定界符#来促进 literal /的使用 - 包含来自{{1}的每一行在comp.log中生成所需的删除命令; /\<...\>/d中输入正则表达式的封闭可确保匹配为单词,如\<...\>所示。 这是需要 GNU grep -w的主要原因,因为POSIX ERE(扩展正则表达式)和BSD / OSX sed都不支持sed和{{1 }}。
      • 但是,您 可以使其适用于BSD / OSX \<,将\>替换为sed-r / {{1 } -E / \<