我有以下字符串:
core1@pci0:2:0:1: class=0x020000 rev=0x00 hdr=0x00 vendor=0x1453
vendor = 'MicSystem'
device = 'controller'
class = network
subclass = ethernet
none65@pci0:2:0:2: class=0x080100 rev=0x00 hdr=0x00 vendor=0x1453
vendor = 'MicSystem'
device = 'interface'
class = base peripheral
subclass = DMA controller
core1@pci0:2:0:1: class=0x020000 rev=0x00 hdr=0x00 vendor=0x1453
vendor = 'MicSystem'
device = 'controller'
class = network
subclass = ethernet
我必须删除“class = Base Peripheral”之前的 3 行和之后的 1 行,例如:
core1@pci0:2:0:1: class=0x020000 rev=0x00 hdr=0x00 vendor=0x1453
vendor = 'MicSystem'
device = 'controller'
class = network
subclass = ethernet
core1@pci0:2:0:1: class=0x020000 rev=0x00 hdr=0x00 vendor=0x1453
vendor = 'MicSystem'
device = 'controller'
class = network
subclass = ethernet
我没能做到这一点,这是在 FreeBSD 操作系统中完成的。
答案1
答案2
尝试这个awk
:
awk '
FNR==NR && /class[[:blank:]]*=[[:blank:]]*base peripheral/{x=NR; nextfile;}
FNR!=NR && (FNR < x-3 || FNR > x+1)
' file file
送入file
两次awk
。第一次,找到相关行(如果有多个,则仅第一个匹配!)。第二次,打印排除要省略的行的行。
要与命令输出一起使用,请使用:
awk '...' <(command) <(command)
或者
output="$(command)"
awk '...' <(printf '%s' "$output") <(printf '%s' "$output")
答案3
最简单的方法可能如下,在每个 Unix 机器上的任何 shell 中使用任何 awk:
$ cat tst.awk
$0 ~ re {
for (i=(NR-b); i<=(NR+a); i++) {
skip[i]
}
}
{ lines[NR] = $0 }
END {
for (i=1; i<=NR; i++) {
if ( !(i in skip) ) {
print lines[i]
}
}
}
$ awk -v b=3 -v a=1 -v re='class[[:space:]]*=[[:space:]]*base peripheral' -f tst.awk file
core1@pci0:2:0:1: class=0x020000 rev=0x00 hdr=0x00 vendor=0x1453 device=0xa2d2 subvendor=0x1453 subdevice=0x0008
vendor = 'MicSystem'
device = 'controller'
class = network
subclass = ethernet
core1@pci0:2:0:1: class=0x020000 rev=0x00 hdr=0x00 vendor=0x1453 device=0xa2d2 subvendor=0x1453 subdevice=0x0008
vendor = 'MicSystem'
device = 'controller'
class = network
subclass = ethernet
如果您的输入来自管道而不是存储在 shell 中,那么只需执行whatever | awk -v ... -f tst.awk
或执行其他任何操作即可将输入传递给脚本。
与上面的解决方案一样,ed
将整个输入读取到内存中,但如果您的输入不是数亿行那么长,这不会成为问题。如果确实有这种情况,那么您可以实现一个滚动缓冲区,它是一个大小的数组,b
这样当当前行与正则表达式不匹配时,您总是打印该数组中的第一个元素,但这需要更多的思考来编写并进行处理重叠范围更难。
答案4
尽管问题是通过删除该行之前和该行之后的这么多行来描述的,但显然这些预期编辑的效果具有更高级别的含义“删除属性class
具有该值的项目base peripheral
”。
有一种非常适合我们关注较大文档结构的此类转换任务的语言:TXR。
我们可以使用易于其他人或 17 个月后您自己理解的代码来详细完成字段提取:
@(repeat)
@addr: class=0x@cl rev=0x@rev hdr=0x@hdr vendor=0x@ven
vendor = '@vendor'
device = '@device'
class = @class
subclass = @subclass
@ (require (nequal class "base peripheral"))
@ (output)
@addr: class=0x@cl rev=0x@rev hdr=0x@hdr vendor=0x@ven
vendor = '@vendor'
device = '@device'
class = @class
subclass = @subclass
@ (end)
@(end)
跑步:
$ txr data.txr data
core1@pci0:2:0:1: class=0x020000 rev=0x00 hdr=0x00 vendor=0x1453
vendor = 'MicSystem'
device = 'controller'
class = network
subclass = ethernet
core1@pci0:2:0:1: class=0x020000 rev=0x00 hdr=0x00 vendor=0x1453
vendor = 'MicSystem'
device = 'controller'
class = network
subclass = ethernet
在这里,模式匹配断言@(require expr)
就是消除不需要的项目;当为 false 时它会失败expr
。
您可以使过滤变得任意复杂,并根据需要轻松地重塑输出。嵌入式 TXR Lisp 语言也具有神奇的超能力。