Bash grep 换行符

13

[编辑插入:可能是与同一位发布者的早期问题重复?]

你好,我需要从文件中提取:

first
second
third

使用grep命令,以下是一行代码:

second
third

grep命令应该长什么样?


你是字面意思还是想要第二和第三行,无论它们的内容是什么?此外,这是你的作业吗? - Telemachus
不是我的作业,只是一个任务。我不知道如何在这里构建正则表达式。 - Markus
1
我想要构建一个包含换行符的正则表达式。 - Markus
grep 本质上是面向行的。您不需要正则表达式来匹配字面字符串“first”或“second”。让我再问一遍:您想匹配这两个确切的单词还是想匹配第二行和第三行(无论内容如何)?如果您想匹配两行特定的文本,则 Liori 的解决方案之一比 grep 更好。请尽量清楚地解释您想要的内容。 - Telemachus
我想在文件中搜索一系列行,例如“line1\nline2”。 - Markus
如果你想搜索一系列的行并且想要向文件中添加单词,那么 grep 并不是正确的工具。对我来说,这更像是脚本语言的工作,但是如果没有更好的描述真正问题的方式,那么就无法帮助你。请编辑你的问题并展示 (1) 合理真实的数据和 (2) 更完整的解释你想要如何处理这个文件。 - Telemachus
11个回答

21

你可以使用 pcregrep 替代 grep,pcregrep 支持多行匹配模式

pcregrep -M 'second\nthird' file

-M选项允许模式匹配多行。


4
根据文件所使用的行尾符号(有些可能是\r\n),你可能需要使用\s+代替\n - davemyron

9

您的问题摘要是“bash grep newline”,这意味着您想匹配second\nthird字符序列——即包含换行符的内容。

由于grep按“行”工作,而这两个字符序列位于不同的行中,因此您无法以这种方式进行匹配。

因此,我会将其分成几个任务:

  1. you match the line that contains "second" and output the line that has matched and the subsequent line:

    grep -A 1 "second" testfile
    
  2. you translate every other newline into the sequence that is guaranteed not to occur in the input. I think the simplest way to do that would be using perl:

    perl -npe '$x=1-$x; s/\n/##UnUsedSequence##/ if $x;'
    
  3. you do a grep on these lines, this time searching for string ##UnUsedSequence##third:

    grep "##UnUsedSequence##third"
    
  4. you unwrap the unused sequences back into the newlines, sed might be the simplest:

    sed -e 's/##UnUsedSequence##/\n'
    

因此,实现您想要的功能的管道命令如下:

grep -A 1 "second" testfile | perl -npe '$x=1-$x; s/\n/##UnUsedSequence##/ if $x;' | grep "##UnUsedSequence##third" | sed -e 's/##UnUsedSequence##/\n/'

虽然不是最优雅的方法,但应该能够工作。我很好奇是否有更好的方法 - 应该有一些。


3

我认为在这种情况下,grep 不是最好的选择。

如果你只是想从任何文件中删除第一行(为了概括你的问题),我会使用 sed

sed '1d' INPUT_FILE_NAME

这将会把文件内容发送到标准输出,第一行被删除后。然后你可以将标准输出重定向到另一个文件中以捕获结果。
sed '1d' INPUT_FILE_NAME > OUTPUT_FILE_NAME

应该可以了。

如果你必须使用grep,并且不想显示带有first的行,则尝试使用以下方法:

grep -v first INPUT_FILE_NAME 

通过使用-v开关,您告诉grep显示除您传递的表达式之外的所有内容。 实际上,显示除包含first的行之外的所有内容。
然而,缺点是具有多个first的文件也不会显示这些其他行,并且可能不是您预期的行为。
要将结果传输到新文件,请尝试以下操作:
grep -v first INPUT_FILE_NAME > OUTPUT_FILE_NAME

希望这有所帮助。

我认为你可能把最后两个例子搞反了。 - Telemachus

2

我不太明白您想匹配什么。我不会使用grep,而是使用以下其中一种:

tail -2 file         # to get last two lines
head -n +2 file      # to get all but first line
sed -e '2,3p;d' file # to get lines from second to third

(不确定它有多标准,但在GNU工具中肯定有效)

1

所以你只是不想要包含“first”的那行吗?-v会反转grep的结果。

$ echo -e "first\nsecond\nthird\n" | grep -v first
second
third

1

grep -A1 "second" | grep -B1 "third" 运行良好,如果有多个匹配项,它甚至可以去掉原始的匹配分隔符


1

是单数还是复数?

试试看

grep -E -e '(second|third)' filename

编辑:grep 是面向行的。你需要使用 Perl、sed 或 awk 来跨行进行模式匹配。

顺便提一下,-E 告诉 grep 正则表达式是扩展的 RE。


行。但是如何构建一个将被egrep使用的正则表达式呢?换行符如何表示? - Markus
egrep 'second\\nthird' filename - Mike Lowery

0
grep -v '^first' filename

-v标志反转匹配。


0

你可以使用

$ grep -1 third filename

这将打印一个与匹配项有关的字符串,以及前后一个字符串。由于“third”在最后一个字符串中,因此您会得到最后两个字符串。


0

我喜欢notnoop的答案,但是在AndrewY的答案的基础上进行改进(对于那些没有pcregrep的人来说更好,但是太过复杂),你可以这样做:

RESULT=`grep -A1 -s -m1 '^\s*second\s*$' file | grep -s -B1 -m1 '^\s*third\s*$'`

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接