显示所有符合条件的文件


Answers:


95

塞德对此更好。

做就是了:

sed '/PATTERN/q' FILE

它的工作方式如下:

对于每一行,我们查看它是否匹配/PATTERN

  • 如果是,我们将其打印并退出
  • 否则,我们将其打印

这是最有效的解决方案,因为它一看到PATTERN就退出。如果没有q,sed将继续读取文件的其余部分,并且不执行任何操作。对于大文件,可以有所作为。

这个技巧也可以用来模仿head

sed 10q FILE

刚才试了,它只是输出文件的第一行......虽然比赛时间是38行
尼古拉斯·拉乌尔·

对我来说很好。您能举一个实际输入和输出的例子吗?而您正在按原样运行的命令。
Mikel

在编辑之前,我曾尝试过您的命令,它是:sed'/ PATTERN / p; q'文件
Nicolas Raoul

7
如果我不想打印图案匹配的行,该怎么办?
tommy.carstensen

4
@ tommy.carstensen:sed '/PATTERN/Q' FILE将跳过匹配的行。Q是GNU扩展,因此它不适用于任何sed。
Alex O

37

sed 可以取代grep的大部分功能。

sed -n '1,/<pattern>/ p' <file>

这意味着从第一行开始打印,直到匹配图案为止。

几个范围示例

sed -n '/<pattern>/,$ p' <file> # from pattern to end of file
sed -n '/<pattern1>/,/<pattern2>/ p' <file> # from pattern1 to pattern2

3
该命令很好,但是您可以做得更好。这样,它将读取整个文件,但是有可能在找到匹配项后立即退出。
Mikel

3
如果我不想打印图案匹配的行,该怎么办?
tommy.carstensen

34

打印并包括以下匹配项:

awk '{print} /pattern/ {exit}' filename
sed '/pattern/q' filename

最多打印但不包括匹配项:

awk '/pattern/ {exit} {print}' filename
sed '/pattern/Q' filename

11
Q酷但GNU特有的afaik,sed -n '/pattern/!p;//q'会更便携。
don_crissti 2015年

@don_crissti:你应该让一个答案,我认为这是一个很好的(:我有点好奇它是如何工作的,但我相信,!p适用于线匹配pattern,但随后//q混淆了我...
JWD

2
@don_crissti:啊,我明白了– //意思是“先前的正则表达式”(我以为意思是“匹配空字符串”)。我认为相同的解决方案的一个较短的版本是:sed -n '/pattern/q;p
jwd

@jwd-的确如此。👍
don_crissti

1

以下纯GNU grep方法效率不高。

使用三个s 在文件栏中搜索字符串“ foo ” 的第一个实例之前的所有内容:grep

grep -m 1 -B $(grep -n -m 1 foo bar | grep -o '^[0-9]*') foo bar

匹配“ foo ” 的最后一个实例:

grep -oPz "(?s)[^\n]*${s}.*?\n.*?foo.*?\n" bar

注意:有关最后一项的详细信息,请grep参见:正则表达式(grep),需要进行多行搜索


为什么grep只需要运行一次sed调用就为什么要使用7 s(+ pcre)sed 'x;/./G;//!x;/foo/p;//s/.*//;x;d'
don_crissti

@don_crissti,您的sed代码似乎值得其回答,或者可以将其添加到其他代码中。回复7个grepS:因为没有grep答案......(加,得到的答案有助于表明为什么不呢?)
AGC

这不是我的代码,只需单击它...即使这是我的代码,它也无法在此处回答Q,因此我不会将其发布为答案。
don_crissti

1

在上面添加到Mikel的答案中...


要打印所有线路可达,但不包括,第一行FILE包含PATTERN,尝试:

  • sed '/.*PATTERN.*/{s///;q;}' FILE

这将匹配包含模式的整行,将其替换为空白行,然后退出而不处理文件的其余部分。


后记:

我想避免在末尾打印额外的换行符(不涉及其他工具)的最简单/最清晰的方法是再次运行sed并删除新的最后一行:

sed '/.*PATTERN.*/{s///;q;}' FILE | sed '$d'

...并且由于我们现在无论如何都删除该行,因此我们以前的工作是多余的,我们可以简化为:

sed '/PATTERN/q' FILE | sed '$d'

Glenn的答案(以及我在那的评论)展示了如何通过一次sed调用来做到这一点。
don_crissti

(为此,我确实看到了您对agc答案的评论,但是因为我的大脑不喜欢双负数,所以错过了另一个答案或者只是略读了它。)由于我在a tcshbash别名中都使用了它,因此我需要确保有一个相对简洁的单线解决方案,可在标准和GNU中使用sed(出于可移植性);您的贡献很可能满足的所有要求。正如有人谁使用sed 非常罕见,我最重要的要求是什么,当我不想轻易从现在编辑或重新目的,多年来,我可以很快的了解。
吉姆·格里舍姆

1

对于只选择记住日常工作中的基本工具,并愿意接受不太优雅,效率较低的解决方案的人们:

head -n $(grep -n pattern filename | cut -d: -f1) filename

如果此命令用于脚本,那么我将寻找更优雅(且可能高效)的解决方案。如果这是一次性命令或一次性脚本,那么我不在乎。


1
好主意,但是三个命令一起执行。
Mikel

1
知道基本知识确实非常好。不过,了解正确的工作工具会更好。
soulmerge 2011年

如果此命令用于脚本,那么我将寻找更优雅(且可能高效)的解决方案。如果这是一次性命令(或一次性脚本),那么我不在乎。
lesmana 2011年

0

您也可以使用以下之一

tac ./test | grep -B $(cat ./test | wc -l) -m 1 'pattern'|tac 

要么

tac ./test |head -n $(tac ./test | grep -n 'pattern' | cut -d: -f1 | head -n 1)|tac

要么

tac ./test |sed ':a;N;$!ba;s/\n/'"pattern"'/g' | sed 's/'"patternpattern"'/\n/g'|head -n 1|sed 's/'"pattern"'/\n/g'|tac

第一个选项与OP所建议的非常相似,只是它通过计算文件中的行数来确保ti在上下文之前显示足够的行数

第二个选项搜索第一个匹配项的行号(您也可以通过更改内部的“ head”来更改行号),然后在该编号上使用head

最后一个选项将所有新行替换为匹配项,然后将两个相邻的匹配项替换为新行。此输出是两次匹配之间每个文本块的一行。之后,它使用“ head”选择第一行(将文本块更改为第一个匹配项),然后将每个匹配项重新转换为新行。仅当文件采用以下格式时,此选项才有效

pattern
texttexttext
texttexttext texttexttext
texttexttexttexttexttexttexttexttext
pattern
texttexttext
pattern 
texttexttext
texttexttexttexttexttexttexttexttext

依此类推


2
考虑解释这些工作原理,尤其是因为sed底部的命令有点过时。
2015年

第一个选项与OP所建议的非常相似,只不过它通过计算filr中的行数来确保ti在上下文之前显示足够的亲和力
user122778 2015年
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.