【发布时间】:2013-07-28 07:53:58
【问题描述】:
问题:我想在包含匹配模式的行之后直接打印一行。
我的sed 版本不会采用以下语法(它会在+1p 上崩溃),这似乎是一个简单的解决方案:
sed -n '/ABC/,+1p' infile
我认为awk 进行多行处理会更好,但我不知道该怎么做。
【问题讨论】:
问题:我想在包含匹配模式的行之后直接打印一行。
我的sed 版本不会采用以下语法(它会在+1p 上崩溃),这似乎是一个简单的解决方案:
sed -n '/ABC/,+1p' infile
我认为awk 进行多行处理会更好,但我不知道该怎么做。
【问题讨论】:
永远不要使用“模式”这个词,因为它非常模棱两可。始终使用“字符串”或“正则表达式”(或在 shell 中的“通配模式”),无论你是什么意思。
你想要的具体答案是:
awk 'f{print;f=0} /regexp/{f=1}' file
或者在一个正则表达式之后专门化第 N 条记录的更一般的解决方案(下面的成语“c”):
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
我将变量名从“find”的“f”更改为“count”的“c”,其中 合适,因为这更能表达变量的实际含义。
f 是 found 的缩写。当我在输入 (/regexp/{f=1}) 中找到与正则表达式 regexp 匹配的字符串时,它是一个布尔标志,我将其设置为 1 (true)。您在每个脚本中看到 f 的另一个地方是它自己的一个条件,它正在作为条件进行测试,当它为 true 时,会导致 awk 执行其打印当前记录的默认操作。所以输入记录只有在我们看到 regexp 并将f 设置为 1/true 后才会得到输出。
c && c-- { foo } 的意思是“如果c 不为零,则递减它,如果它仍然不为零,则执行foo”,因此如果c 从3 开始,那么它将递减到2,然后foo 执行,在下一个输入行 c 现在是 2,所以它会递减到 1,然后 foo 再次执行,在下一个输入行 c 现在是 1 所以它会是减为 0,但这次 foo 将不会被执行,因为 0 是错误条件。我们使用c && c-- 而不是只测试c-- > 0,因此我们不会遇到输入文件很大的情况,其中c 达到零并继续递减,因此它经常回绕并再次变为正数。
【讨论】:
after 是您感兴趣的匹配项,对吧?在 sed 中,可以这样完成:
sed -n '/ABC/{n;p}' infile
或者,grep 的 A 选项可能是您正在寻找的。p>
-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
希望对您有所帮助。
【讨论】:
{n;p} 似乎受 GNU sed 支持,但不支持 BSD sed。 (感谢 sed 的回答 chooban。我非常尊重 awk,并且使用过它,但我尽量避免重新学习它的巴洛克语言。(当我需要 awk 时,我使用 perl)。)
;:sed -n /bar/{n;p;} 成功使用了 BSD sed。也适用于 GNU sed。
sed -n '/bar/{;n;p;}',因为 { 和 } 的解析方式与字母命令完全相同。
我需要在模式之后打印所有行(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
我真的应该在这个答案中包含 tlwhitec 的评论(因为他们的 sed-strict 方法比我的建议更优雅):
sed '0,/pattern/d'
上面的脚本会删除从第一行开始到(包括)与模式匹配的行为止的每一行。打印之后的所有行。
【讨论】:
sed '0,/regex/d'
/start/,/end/) 的原因,这意味着您不要使用 sed 执行此类任务,因为它没有变量,所以您只需要剩下的是范围。您想要做的就是排除开始或结束行,它需要您添加管道和其他命令来执行此操作 vs awk '/start/{f=1} f; /end/{f=0}' - 只需重新排列要打印的块或不打印开始/结束部分,不需要额外的工具或管道.
awk 版本:
awk '/regexp/ { getline; print $0; }' filetosearch
【讨论】:
getline之前,请确保您已准备好并完全理解awk.info/?tip/getline。
如果模式匹配,将下一行复制到模式缓冲区,删除一个返回,然后退出——副作用是打印。
sed '/pattern/ { N; s/.*\n//; q }; d'
【讨论】:
q 绝不是 GNU 扩展。这是一个标准的sed 命令。
p 而不是 q。
如果pattern匹配continuous行,实际上sed -n '/pattern/{n;p}' filename会失败:
$ 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
解释:
x;:在输入的每一行开头,使用x命令交换pattern space&hold space中的内容。/_/{x;p;x};:如果pattern space,实际上是hold space,包含_(这只是一个indicator,表示最后一行是否匹配pattern),然后使用x交换current line到pattern space的实际内容,使用p打印current line,x恢复这个操作。 x:恢复pattern space和hold space中的内容。/pattern/!s/.*//:如果current line不匹配pattern,这意味着我们不应该打印下一行,然后使用s/.*//命令删除pattern space中的所有内容。/pattern/s/.*/_/:如果current line匹配pattern,这意味着我们应该打印下一行,那么我们需要设置一个indicator来告诉sed打印下一行,所以用s/.*/_/替换所有pattern space 中的内容到_(第二个命令将使用它来判断最后一行是否匹配pattern)。h:用pattern space中的内容覆盖hold space;那么hold space中的内容就是^_$,表示current line匹配pattern,或者^$,表示current line不匹配pattern。s/.*/_/之后,pattern space不能匹配/pattern/,所以s/.*//必须执行!【讨论】:
这可能对你有用(GNU sed):
sed -n ':a;/regexp/{n;h;p;x;ba}' file
使用 seds 类似 grep 的选项 -n 如果当前行包含所需的正则表达式,则将当前行替换为下一行,将该行复制到保留空间(HS),打印该行,交换模式空间(PS ) 用于 HS 并重复。
【讨论】:
管道一些 grep 可以做到(它在 POSIX shell 和 BusyBox 下运行):
cat my-file | grep -A1 my-regexp | grep -v -- '--' | grep -v my-regexp
-v 将显示不匹配的行【讨论】: