Linux 需要grep/awk/gawk返回整个部分,尽管有断线

Linux 需要grep/awk/gawk返回整个部分,尽管有断线,linux,awk,grep,find,gawk,Linux,Awk,Grep,Find,Gawk,我有以下问题。。。 我有一个类似于此的文件: 2018-04-25: line1 2018-04-25: line2 this is another line I'm a line 2018-04-25: line3 2018-04-25: line4 如果我运行:grep'this'test.log,结果将是: this is another line 但我需要的结果是: 2018-04-25: line2 this is anoth

我有以下问题。。。 我有一个类似于此的文件:

2018-04-25: line1
2018-04-25: line2
        this is another line
        I'm a line
2018-04-25: line3
2018-04-25: line4
如果我运行:grep'this'test.log,结果将是:

    this is another line
但我需要的结果是:

2018-04-25: line2
        this is another line
        I'm a line
因为“这是另一行”实际上是同一条记录的一部分,唯一的问题是我们在那里有一个换行符,我需要我的grep忽略这个换行符

  • grep-C 1“this”test.log
  • grep-b1“this”test.log
不是一个真正的选项,因为在条目的开始和结束之间可能有更多的行/换行符。

如果这是输入:

2018-04-25: line1
2018-04-25: line2
        this is another line
        I'm a line
2018-04-25: line3
2018-04-25: line4
您可以使用:
grep-A2 line2 file.log
,它将返回:

2018-04-25: line2
        this is another line
        I'm a line
-A
代表上下文之后的
,来自man:

-A num, --after-context=num
         Print num lines of trailing context after each match. 
或者,如果使用
作为模式,则可以混合使用
-B
-a
,例如:

grep -B1 -A1 this file.log

这里有一种使用GNU awk的方法:行开头的日期是记录分隔符。对于包含模式的记录,打印上一个记录分隔符和当前记录

gawk -v RS='(^|\n)[0-9-]{10}' '
    /this/ {sub(/^\n/, "", prev_RT); print prev_RT $0} 
    {prev_RT = RT}
' file
或者,更直接一些

awk '
    function printif() {if (record ~ /this/) print record}
    /^[0-9-]{10}/ {printif(); record = ""} 
    {record = (record ? record "\n" : "") $0} 
    END {printif()}
' file

对于给定的示例,这将起作用

$ gawk -v ORS= -v RS='2018-' '/this/{print RS $0}' ip.txt
2018-04-25: line2
        this is another line
        I'm a line
  • -v ORS=
    清除输出记录分隔符
  • -v RS='2018-'
    2018-
    设置为输入记录分隔符(假设所有记录的年份相同)
  • /this/{print RS$0}
    如果记录包含
    this
    ,请打印记录分隔符和记录内容

另一个多行awk版本:

#!/usr/bin/awk -f    

# When the line is starting with the time string
# a new record is starting...
/^[[:digit:]]{4}(-[[:digit:]]{2}){2}/ {
    # Check if the (b)uffer matches /this/
    if(b~/this/)
       # ... and print it in that case
       print b

    # Empty the buffer in any case
    b="" 
}

# Append each line to the buffer
{b=b""ORS""$0}

它应该适用于任何版本的awk。

为了完成此任务,我们还可以使用
sed
以更隐秘的方式完成此任务:

 sed -n '/[-0-9]\{10\}:/{x;/this/p;d};H;${x;/this/p}' <file>

grep
将起始行与
-b1
隔开:

$ grep -B 1 "^ " file
2018-04-25: line2
        this is another line
        I'm a line

如果空间不够:
grep-b1-v“^[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}:“文件

从正则表达式匹配到另一个正则表达式:

awk '/line2/{f=1} f;/I\47m a line/{f=0}' file 

2018-04-25: line2
        this is another line
        I'm a line

可能是
RS=“\n2018-”
,这样可以避免记录条目本身包含
2018-
@kvantour而不包含第一行的情况。。。有关稳健性,请参见glenn的答案。
RS='(^ |\n)2018-“
将解决此问题。@karakfa需要更改打印stmt或处理RT。。。这将导致类似于格伦的答案:)我是故意尝试基于给定样本的更简单的答案;)不能真正使用A/B,因为行是可变的谁在这里投票?我看不出有什么原因。嗯,有一个通常的嫌疑犯。非常神秘的詹姆斯。想详细说明一下吗?@glennjackman是一位活跃的成员,他对所有他认为没有达到预期的问题都投了反对票。主要是脚本和shell工具相关的问题。嗯,我想惩罚回答者的“罪过”。艰苦的爱。哦,这是@nbari解决方案(++)的一个变体。
$ grep -B 1 "^ " file
2018-04-25: line2
        this is another line
        I'm a line
awk '/line2/{f=1} f;/I\47m a line/{f=0}' file 

2018-04-25: line2
        this is another line
        I'm a line