使用awk打印除匹配范围模式外的所有内容

5
在Awk中,范围模式不是一个表达式,因此不能使用“!”来否定它。那么如何实现(使用awk打印所有内容,除了匹配范围模式的内容)? 例如: $cat 1.t
abd
hfdh
#  
fafa
deafa
123 
#
end

我理解您需要的翻译如下:

我想要的结果:

猫1.t

abd
hfdh
end

编辑:

我给了一个不恰当的例子。结束模式应该与开始模式不同,因为我没有测试过这个。这是我的错。

同时,我想要对范围模式和非范围模式进行不同的操作。所以sed不是我的选择。


2
+1 对于你的棘手示例文本! - Kent
3个回答

7
你刚才给出了一个棘手的(我不知道该称其为好还是坏^_^)例子。你的文本正好有相同的开始模式和结束模式(#)。
我猜你正在寻找与sed '/#/,/#/d'或sed -n '/#/,/#/!p'相同的方法。
在awk中有一些类似(不同于sed的)地址模型。在man页面中有解释。我说的不同,你的例子很好。如果start == end,则awk的地址模型将无法工作:
kent$  echo "abd
hfdh
#  
fafa
deafa
123 
#
end"|awk '/#/,/#/{next}1'                                                                                                                                                   
abd
hfdh
fafa
deafa
123 
end

因为awk匹配的是同一行(请参阅man页面),但如果它们不同,请看这个例子:

kent$  echo "abd
hfdh
#  
fafa
deafa
123 
##
end"|awk '/#/,/##/{next}1'
abd
hfdh
end

它会给你想要的东西。所以如果是这种情况,你可以直接做如下操作:

awk '/start/,/end/{next}1'

是的,与sed相似。

如果起始和结束真的相同,你需要使用带有标志的awk来完成。

kent$  echo "abd
hfdh
#  
fafa
deafa
123 
#
end"|awk '/#/&&!f{f=1;next}f&&/#/{f=0;next}!f'
abd
hfdh
end

好的,在这个例子中最好使用^#$,但这不是重点。我希望这回答了你的问题。


awk '/start/,/end/{next}1' 这是一个用来处理文本的 AWK 命令。它的作用是在匹配到 "start" 和 "end" 之间的行时跳过这些行,然后输出其他所有行。尽管这个例子可能有点别扭,但它对于回答你的问题是正确且详细的。虽然我没有清楚地解释,但希望这个例子能帮到你! - Zhilong Jia

1

sed是一种替代方案吗?

$ sed '/#/,/#/d' input
abd
hfdh
end

1
如果你确实需要使用 awk,可以尝试以下方法:
awk 'BEGIN{x=1} /startpattern/{x=0} /endpattern/{x=1;next} x{print}'

尽管 sed 替代方案可能是一种更简单的方法(至少打字更少)。
编辑:@Kent 指出您具有相同的起始和结束模式,这使得它有些棘手,但这应该可以工作:
awk 'BEGIN{x=1} /pattern/{x=!x;next} x{print}'

基本上,每次看到这个模式,它就会切换x,并且只有在x!=0时才会打印。其中的“next”避免了在打印被打开时打印该模式。

这个不适用于 OP 的例子,因为它具有相同的起始和结束模式。你需要检查 x 不仅用于打印,还要用于设置 x 本身。 - Kent
@Kent 很好的发现... 编辑了一个考虑到这一点的替代版本。 - twalberg

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