搜索字符串并打印范围内前后的所有内容


9

我有这个文件:

sometext1{
string1
}

sometext2{
string2
string3
}

sometext3{
string4
string5
string6
}

我想在该文件中搜索特定的字符串,并在此字符串之前将所有内容打印到开头,{并在此字符串之后将所有内容打印到结尾}。我尝试使用sed实现此目的,但是如果尝试打印/{/,/string2/sed 范围内的所有内容,例如sed会打印以下内容:

sometext1{
string1
}

sometext2{
string2
sometext3{
string4
string5
string6
}

如果我搜索字符串“ string2”,则需要输出为:

sometext2{
string2
string3
}

谢谢。


好吧,现在我发现我需要原始文件中输出的行号,以便以后删除它们。我尝试更改@mikeserv提供的命令,但是运气不好,我对sed的hold函数有些困惑。
rodrigo 2015年

好吧,Geez,Rodrigo,你没有告诉任何人,但你自己。可以做到,但最好像这样完成grep -n '' <infile | sed ...。这些sed命令将需要修改;特别是寻找行顶锚的/地址/^。因此,如果您使用我的答案,则可以执行:grep -n '' | sed 'H;/{$/h;/^[^:]*:}/x;/{\n.*PATTERN/!d'。所有输出行都将以原始文件的行号作为前缀,后跟冒号等1:sometext1{\n2:string1sed将仅过滤之前过滤的内容,不同之处在于每条输出行均以数字开头。
mikeserv

Answers:


9

这是两个命令。如果您想要一个命令来修剪.*{$序列中的最后一行(如@don_crissti所做的那样ed,则可以执行以下操作:

sed 'H;/{$/h;/^}/x;/{\n.*PATTERN/!d'

...的工作原理是,将每行附加到H一个\newline字符之后的h旧空间上,覆盖匹配的每行旧空间{$,并为匹配的每行交换h旧空间和模式空间^},从而刷新其缓冲区。

它只打印与ewline 匹配的行,{然后再匹配-在缓冲区交换之后立即发生。\nPATTERN

它将一系列{$匹配中的任何行都排到了序列中的最后一行,但是您可以获得所有包含在内的内容,例如:

sed '/PATTERN.*\n/p;//g;/{$/,/^}/H;//x;D'

它的作用是h为每个...{$.*^}.*序列交换图案和旧空间,将序列中的所有行附加到H一个\newline字符之后的旧空间中,并在每个行周期内升至模式空间中D第一个出现的\newline字符,然后再重新开始剩余的字符。

当然,只有\n在输入空间匹配^}时(范围的末尾),才在模式空间中使行缩线,因此,当它在任何其他情况下重新运行脚本时,它通常仅会拉入下一个输入行。

但是,当PATTERN在与\newline 相同的模式空间中找到when时,它将打印很多内容,然后^}再次覆盖它(这样它可以结束范围并刷新缓冲区)

给定这个输入文件(感谢don)

sometext1{
string1
}

sometext2{
PATTERN
string3
}

sometext3{
string4
string5
string6
}

Header{
sometext4{
some string

string unknown

here's PATTERN and PATTERN again
and PATTERN too
another string here
}
}

第一版画:

sometext2{
PATTERN
string3
}
sometext4{
some string

string unknown

here's PATTERN and PATTERN again
and PATTERN too
another string here
}

...还有第二个...

sometext2{
PATTERN
string3
}
Header{
sometext4{
some string

string unknown

here's PATTERN and PATTERN again
and PATTERN too
another string here
}

@don_crissti-我不知道 它仅对以开头的行定界}。这可能会有益于…… open{\nsub;\n{ command; }\n}; close-但我不确定这是怎么回事……
mikeserv 2014年

@mikeserv大家好-我在unix.stackexchange.com/questions/232509/…处提出了类似的问题,您的解决方案适用于小文件,但是我有一个大文件,并且我正在“保持空间溢出”。错误信息。您知道吗,我该如何解决?非常感谢
Narayan Akhade 2015年

@NarayanAkhade-不 无论如何,并非没有大修。除非...有没有包含在{...}块中的大量输入?如果是这种情况,并且您正在使用第一个解决方案,那么您可能会/{$/,/^}/H在一开始就这样做,而不仅仅是H。但是,如果您也尝试了第二种解决方案,但仍然遇到相同的错误,则该解决方案将无济于事,因为该解决方案已经做到了。也不要打折ed。唐的有一个非常好这里的答案,并且ed可以适用于使用临时缓存文件非常简单为好,这应防止MEM缓冲区溢出。
mikeserv

6

这是一个解决方案ed

ed -s filename <<< $'g/PATTERN/?{?,/}/p\nq\n'

那是:

g/PATTERN/     # mark each line matching PATTERN  
?{?,/}/p       # for each marked line, print all lines from the previous { up to the next }  
q              # quit editor

假设PATTERN每对之间只有一行,{ }否则您将获得PATTERN同一块内部每增加一行的重复输出。
它适用于多个{ }包含单行匹配的内容,PATTERN例如,对于具有PATTERN两个不同部分的测试文件:

sometext1{
string1
}

sometext2{
PATTERN
string3
}

sometext3{
string4
string5
string6
}

Header{
sometext4{
some string

string unknown

here's PATTERN again

another string here
}
}

跑步

ed -s sample <<< $'g/PATTERN/?{?,/}/p\nq\n'

输出:

sometext2{
PATTERN
string3
}
sometext4{
some string

string unknown

here's PATTERN again

another string here
}

实际上,我从中学到了很多!非常感谢!
mikeserv 2014年

我什至不知道该命令存在。谢谢
rodrigo 2014年

4

pcregrep

pcregrep -M '(?s)\{[^}]*PATTERN.*?\}'

或使用GNU grep提供的输入不包含NUL字节:

grep -Poz '.*(?s)\{[^}]*PATTERN.*?\}'

0
$ awk 'BEGIN{RS="\n\n"; FS="[{}]"} {if ($2 ~ /string4/) {print $2}}' t1.txt
string4
string5
string6

哪里:

  • string4 ->要匹配的字符串
  • t1.txt ->包含查询中提到的文件内容

-2

sed -n'/ 字符串 / p' 文件名

-n当添加到sed时抑制了sed的默认行为,此语句可能无法完全提供所需的内容,但应替换字符串

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.