![在文本文件中查找特定模式并将其从输出中排除?](https://linux22.com/image/128138/%E5%9C%A8%E6%96%87%E6%9C%AC%E6%96%87%E4%BB%B6%E4%B8%AD%E6%9F%A5%E6%89%BE%E7%89%B9%E5%AE%9A%E6%A8%A1%E5%BC%8F%E5%B9%B6%E5%B0%86%E5%85%B6%E4%BB%8E%E8%BE%93%E5%87%BA%E4%B8%AD%E6%8E%92%E9%99%A4%EF%BC%9F.png)
我有一个大约 25000 行的文件。看看我的示例输入和所需的输出
输入:
zone name tommy
* pwwn xxxxxxxx
pwwn xyzabcda
* pwwn xcvuytnm
zone name sammy
* pwwn akslapsl
* pwwn dfgsjasl
* pwwn xcvuytnm
zone name angelfalls
* pwwn xxxxxxxx
pwwn xyzabcda
zone name Newyork
* pwwn xxxxxxxx
pwwn xyzabcda
期望的输出:
zone name tommy
* pwwn xxxxxxxx
pwwn xyzabcda
* pwwn xcvuytnm
zone name angelfalls
* pwwn xxxxxxxx
pwwn xyzabcda
zone name Newyork
* pwwn xxxxxxxx
pwwn xyzabcda
我希望输出排除 pwwn 之前每一行中包含 * 的所有区域。在我的示例中,区域名称 sammy 在所有三个 pwwn 行中都有一个 *,因此我排除了区域名称 sammy 下的所有 * 行。
使用Solaris 5.10、Korn Shell。
答案1
Awk
解决方案:
awk '/^zone /{
if (f) print r;
r = $0; f = 0; next
}
{ r = r ORS $0; if (/^[^*]* pwwn/) f = 1; }
END{ if (f) print r }' file
输出:
zone name tommy
* pwwn xxxxxxxx
pwwn xyzabcda
* pwwn xcvuytnm
zone name angelfalls
* pwwn xxxxxxxx
pwwn xyzabcda
zone name Newyork
* pwwn xxxxxxxx
pwwn xyzabcda
答案2
以下是我如何将其作为快速 Perl 管道来实现的:
perl -p00e 's/\nzone/\n\nzone/g' inputfile \
| perl -n00e '$t = $_; s/^\*.*?\n//mg; print $t if /pwwn/' \
| perl -p00e 's/\n\n/\n/'
第一行在每个记录之间添加一个空行。第二行迭代每个记录,检查pwwn
删除该记录中以 * 开头的所有行后是否还有剩余行,如果有,则打印该记录。第三行删除分隔每条记录的空行。
答案3
$ awk -v RS='(^|\n)zone' '/\n[^*]/ { print "zone" $0 }' input
zone name tommy
* pwwn xxxxxxxx
pwwn xyzabcda
* pwwn xcvuytnm
zone name angelfalls
* pwwn xxxxxxxx
pwwn xyzabcda
zone name Newyork
* pwwn xxxxxxxx
pwwn xyzabcda
该awk
脚本将记录分隔符 ( RS
) 设置为输入文件的开头或换行符,后跟单词“zone”。然后它打印每条“记录”,其中至少包含一个换行符,后面没有*
.
它必须打印单词“zone”,$0
因为会自动从每个输入记录中awk
删除“zone ”。RS
注意:因为RS
它本身不仅仅是换行符,还$0
包含每行输入末尾的换行符(这与上面提到的必须打印“zone”的原因密切相关)。这意味着输出的最后会有一个额外的空行。如果这是一个问题,解决它的最简单方法是使用sed
.例如
awk -v RS='(^|\n)zone' '/\n[^*]/ { print "zone" $0 }' input | sed '$d'
最后,如果pwwn
是匹配条件的重要部分,则将脚本中的正则表达式匹配从 更改/\n[^*]/
为/\n[^*] pwwn/
。 (给定样本输入后,输出是相同的,但可能与更大的实际输入不同)