使用sed或awk按照匹配模式打印一行

时间:2013-07-28 13:10:00

标签: awk sed

问题:我想在包含匹配模式的行后面直接打印一行。

我的sed版本不会采用以下语法(它会在+1p上轰炸),这似乎是一个简单的解决方案:

sed -n '/ABC/,+1p' infile

我认为awk会更好地进行多线处理,但我不知道该怎么做。

8 个答案:

答案 0 :(得分:118)

永远不要使用“模式”这个词,因为它非常含糊不清。始终使用“string”或“regexp”(或在shell中使用“globbing pattern”),无论你的意思是什么。

您想要的具体答案是:

awk 'f{print;f=0} /regexp/{f=1}' file

或者在regexp(下面的成语“c”)之后专门化第N条记录的更一般的解决方案:

awk 'c&&!--c; /regexp/{c=1}' file

以下习语描述了如何在给定特定正则表达式匹配的情况下选择一系列记录:

a)打印来自某些正则表达式的所有记录:

awk '/regexp/{f=1}f' file

b)在一些正则表达式后打印所有记录:

awk 'f;/regexp/{f=1}' file

c)在一些正则表达式后打印第N条记录:

awk 'c&&!--c;/regexp/{c=N}' file

d)在一些正则表达式后打印除第N条记录以外的每条记录:

awk 'c&&!--c{next}/regexp/{c=N}1' file

e)在一些正则表达式后打印N条记录:

awk 'c&&c--;/regexp/{c=N}' file

f)在一些正则表达式之后打印除N条记录之外的所有记录:

awk 'c&&c--{next}/regexp/{c=N}1' file

g)打印来自某些正则表达式的N条记录:

awk '/regexp/{c=N}c&&c--' file

我将变量名称从“f”更改为“found”到“c”更改为“count” 适当的,因为它更能表达变量实际上是什么。

答案 1 :(得分:35)

之后的行与您感兴趣的匹配,对吗?在sed中,可以这样完成:

sed -n '/ABC/{n;p}' infile

或者,grep的 A 选项可能就是您要找的。

-A NUM, Print NUM lines of trailing context after matching lines.

例如,给定以下输入文件:

foo
bar
baz
bash
bongo

您可以使用以下内容:

$ grep -A 1 "bar" file
bar
baz
$ sed -n '/bar/{n;p}' file
baz

希望有所帮助。

答案 2 :(得分:3)

我需要在模式之后打印所有行(ok Ed,REGEX),所以我选择了这一行:

sed -n '/pattern/,$p' # prints all lines after ( and including ) the pattern

但是因为我想打印所有的线条(并排除图案)

sed -n '/pattern/,$p' | tail -n+2  # all lines after first occurrence of pattern

我想在你的情况下你可以在最后添加head -1

sed -n '/pattern/,$p' | tail -n+2 | head -1 # prints line after pattern

答案 3 :(得分:2)

awk版本:

awk '/regexp/ { getline; print $0; }' filetosearch

答案 4 :(得分:1)

如果模式匹配,将下一行复制到模式缓冲区,删除一个返回,然后退出 - 副作用就是打印。

sed '/pattern/ { N; s/.*\n//; q }; d'

答案 5 :(得分:1)

如果sed -n '/pattern/{n;p}' filename匹配pattern行,continuous实际上会失败:

$ seq 15 |sed -n '/1/{n;p}'
2
11
13
15

预期的答案应该是:

2
11
12
13
14
15

我的解决方案是:

$ sed -n -r 'x;/_/{x;p;x};x;/pattern/!s/.*//;/pattern/s/.*/_/;h' filename

例如:

$ seq 15 |sed -n -r 'x;/_/{x;p;x};x;/1/!s/.*//;/1/s/.*/_/;h'
2
11
12
13
14
15

说明:

  1. x;:在输入的每一行的开头,使用x命令交换pattern space&中的内容。 hold space
  2. /_/{x;p;x};:如果pattern space实际上是hold space,则包含_(这只是indicator,表示最后一行是否与{{{1}匹配1}}或者没有),然后使用patternx的实际内容交换为current line,使用pattern space打印p,{{1恢复此操作。
  3. current line:恢复xx
  4. 中的内容
  5. pattern space:如果hold space/pattern/!s/.*//不匹配,这意味着我们不应该打印下一行的NEXT,然后使用current line命令删除pattern中的所有内容1}}。
  6. s/.*//:如果pattern space/pattern/s/.*/_/匹配,这意味着我们应该打印下一行的NEXT,那么我们需要设置current line来告诉pattern要打印NEXT行,请使用indicatorsed中的所有内容替换为s/.*/_/(第二个命令将使用它来判断最后一行是否与pattern space匹配)。
  7. _:使用pattern中的内容覆盖h;那么,hold space中的内容为pattern space,这意味着hold space^_$current line匹配,这意味着pattern^$不匹配{1}}。
  8. 第五步和第六步无法交换,因为在current line之后,pattern无法与s/.*/_/匹配,因此必须执行pattern space

答案 6 :(得分:1)

这可能适合你(GNU sed):

sed -n ':a;/regexp/{n;h;p;x;ba}' file

使用seds grep-like选项-n,如果当前行包含所需的正则表达式,则将当前行替换为下一行,将该行复制到保留空间(HS),打印行,交换模式空间(PS)为HS并重复。

答案 7 :(得分:0)

通过一些抓取就可以做到这一点(它在POSIX shell中和BusyBox下运行):

cat my-file | grep -A1 my-regexp | grep -v -- '--' | grep -v my-regexp
  1. -v将显示不匹配的行
  2. -由grep打印,以分隔每个匹配项,因此我们也跳过了