找到一个模式并在其之前 2 行和之后 1 行的开头插入 #

找到一个模式并在其之前 2 行和之后 1 行的开头插入 #

我有一个大文件(超过 2000 行)。找到模式后,我必须在上面 2 行的开头和下面 1 行的开头插入 # 。还在找到模式的行的开头插入#。环境是Red Hat Linux。另外,如果您能解释一下,那就太好了。

举个例子,请参阅下面的文本,搜索“Fail”以及该字符串之前的 # 2 行和该字符串之后的 1 行(行首)。另外 # 行包含字符串“Fail”。

Name
Number
Reason = Pass
Reasult
Name
Number
Reason = Pass
Reasult
Name
Number
Reason = Fail
Reasult
Name
Number
Reason = Pass
Reasult
Name
Number
Reason = Fail
Reasult
Name
Number
Reason = Pass
Reasult

答案1

我建议使用perl

perl -p0e 's/(.*\n)(.*\n)(.*Fail\n)/#\1#\2#\3#/g' file

下面是它的工作原理:

  • -p:在所有输入行上循环打印程序
  • -0: 假设 null 作为记录分隔符
  • -e:从命令行执行程序
  • s/x/y/g:在文件中的任意位置用 y 替换 x
  • ():将正则表达式组合在一起
  • .*:除换行符之外的任何字符重复零次或多次
  • \n: 新队
  • \1, \2, \3: 第 n 组的访问模式()

输出:

Name
Number
Reason = Pass
Reasult
Name
Number
Reason = Pass
Reasult
#Name
#Number
#Reason = Fail
#Reasult
Name
Number
Reason = Pass
Reasult
#Name
#Number
#Reason = Fail
#Reasult
Name
Number
Reason = Pass
Reasult

答案2

这是sed使用滑动窗口的解决方案(因此模式空间中一次不会超过四行):

sed '1{N;N;};$!N;/.*\n.*\n.*Fail.*\n.*/{s/^/#/;s/\n/&#/g;};P;D' infile

在第一行,它读入N后两行(所以现在模式空间中有三行)。
然后,对于每个输入行(包括第一行),它都会拉入Next 行(因此现在模式空间中有四行)。如果模式空间中的第三行匹配Fail,它会在模式空间中的每一行前面添加一个#。然后,无论如何,它P都会 rint 到第一个\newline,然后Deletes 到第一个\newline,重新开始循环。

答案3

$ sed -r 'H;1h;$!d;x; s/\n([^\n]*)\n([^\n]*)\n([^\n]*Fail[^\n]*)\n/\n#\1\n#\2\n#\3\n#/g' file
Name
Number
Reason = Pass
Reasult
Name
Number
Reason = Pass
Reasult
#Name
#Number
#Reason = Fail
#Reasult
Name
Number
Reason = Pass
Reasult
#Name
#Number
#Reason = Fail
#Reasult
Name
Number
Reason = Pass
Reasult

怎么运行的

  • H;1h;$!d;x

    这些命令读取整个文件。

  • s/\n([^\n]*)\n([^\n]*)\n([^\n]*Fail[^\n]*)\n/\n#\1\n#\2\n#\3\n#/g

    Fail这将查找第三行中的连续四行。如果找到,则将#其放置在每个换行符之后。

    更详细地说,替换命令看起来像正则表达式s/old/newwhere 。old在我们的例子中,它是\n([^\n]*)\n([^\n]*)\n([^\n]*Fail[^\n]*)\n。让我们将其分为四个部分:

    1. \n([^\n]*)找到第一行并将其保存在组 1 中。

    2. \n([^\n]*)找到第二行并将其保存在组 2 中。

    3. \n([^\n]*Fail[^\n]*)查找第三行,但仅当该行包含该单词时才匹配Fail

    4. \n匹配第四个换行符。 (第四行的文本未保存:我们不需要它。)

    如果有四行与上面的匹配,那么我们将它们替换为\n#\1\n#\2\n#\3\n#输入相同的内容,除了#在每个换行符之后添加的\n

    Mac OSX (BSD)

以上是在 GNU sed 上测试的。如果使用 BSD sed,请尝试:

sed -E 'H;1h;$!d;x; s/\n([^\n]*)\n([^\n]*)\n([^\n]*Fail[^\n]*)\n/\n#\1\n#\2\n#\3\n#/g' file

答案4

更简单的变体@don_crissti的脚本

sed ':a;/\(.*\n\)\{2\}/{P;D};N;/= Fail$/! ba;N;s/^/# /gm'

相关内容