Sed脚本匹配条件在文件末尾失败

Sed脚本匹配条件在文件末尾失败,sed,Sed,我正在使用以下脚本使ip addr每个接口打印一行: ip addr | sed -nr '/^\w+: /{ H :top n /^\s/ { H ; b top } x s/\n//g a \ ========== p b top } ' 输入: 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN link/lo

我正在使用以下脚本使
ip addr
每个接口打印一行:

ip addr | sed -nr '/^\w+: /{
    H
    :top
    n
    /^\s/ { H ; b top }
    x
    s/\n//g
    a \ ==========
    p
    b top
  }
'
输入:

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth2: <BROADCAST,MULTICAST,NOARP,PROMISC,UP,LOWER_UP> mtu 1600 qdisc pfifo_fast state UP qlen 1000
    link/ether 08:00:27:33:58:cb brd ff:ff:ff:ff:ff:ff
    inet6 fe80::a00:27ff:fe33:58cb/64 scope link
       valid_lft forever preferred_lft forever
3: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 08:00:27:33:58:ca brd ff:ff:ff:ff:ff:ff
    inet 192.168.122.10/24 brd 192.168.122.255 scope global eth0
    inet6 fe80::a00:27ff:fe33:58ca/64 scope link
1:lo:mtu 65536 qdisc noqueue状态未知
链接/环回00:00:00:00:00 brd 00:00:00:00:00:00:00
inet 127.0.0.1/8范围主机lo
inet6::1/128作用域主机
永远有效\u lft首选\u lft永远有效
2:eth2:mtu 1600 qdisc pfifo_快速状态升级qlen 1000
链接/以太08:00:27:33:58:cb brd ff:ff:ff:ff:ff:ff:ff
inet6 fe80::a00:27ff:fe33:58cb/64范围链接
永远有效\u lft首选\u lft永远有效
3:eth0:mtu 1500 qdisc pfifo_快速状态升级qlen 1000
链接/以太08:00:27:33:58:ca brd ff:ff:ff:ff:ff:ff:ff
inet 192.168.122.10/24 brd 192.168.122.255作用域全局eth0
inet6 fe80::a00:27ff:fe33:58ca/64范围链接
输出:

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN     link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00    inet 127.0.0.1/8 scope host lo    inet6 ::1/128 scope host        valid_lft forever preferred_lft forever
 ==========
2: eth2: <BROADCAST,MULTICAST,NOARP,PROMISC,UP,LOWER_UP> mtu 1600 qdisc pfifo_fast state UP qlen 1000    link/ether 08:00:27:33:58:cb brd ff:ff:ff:ff:ff:ff    inet6 fe80::a00:27ff:fe33:58cb/64 scope link        valid_lft forever preferred_lft forever
 ==========
1:lo:mtu 65536 qdisc noqueue状态未知链接/环回00:00:00:00:00:00 brd 00:00:00:00:00 inet 127.0.0.1/8作用域主机lo inet 6::1/128作用域主机有效\u lft永远首选\u lft永远
==========
2:eth2:mtu 1600 qdisc pfifo\u快速状态升级qlen 1000链路/以太08:00:27:33:58:cb brd ff:ff:ff:ff:ff:ff:ff inet6 fe80::a00:27ff:fe33:58cb/64作用域链路永久有效\u lft首选\u lft永久
==========

错误:最后一个接口总是丢失。如何修复它?

这里的问题是
n
的行为

发件人:

n

如果未禁用“自动打印”,请打印图案空间,然后无论如何,用下一行输入替换图案空间。如果没有更多的输入,那么sed将退出,而不处理更多的命令

所以你没有机会对最后一个字段做任何事情,因为sed过早地离开了你。对于
n
来说,这似乎是非常奇怪的行为,但事实就是这样

使用
awk
可以很容易地做到这一点:

ip addr show | awk '/^\w+: / {
        if (iface) {print iface}
        iface=$0
        next
    }
    {iface=iface OFS $0}
    END {print iface}'

但是根据您接下来需要做什么,直接在
awk
中进行所有处理可能同样容易。

这里的问题是
n
的行为

发件人:

n

如果未禁用“自动打印”,请打印图案空间,然后无论如何,用下一行输入替换图案空间。如果没有更多的输入,那么sed将退出,而不处理更多的命令

所以你没有机会对最后一个字段做任何事情,因为sed过早地离开了你。对于
n
来说,这似乎是非常奇怪的行为,但事实就是这样

使用
awk
可以很容易地做到这一点:

ip addr show | awk '/^\w+: / {
        if (iface) {print iface}
        iface=$0
        next
    }
    {iface=iface OFS $0}
    END {print iface}'

但是,根据您接下来需要做什么,直接在
awk
中进行所有处理可能同样容易。

天哪,只要使用
awk

$ awk -v RS= '{gsub(/\n\s+/," ")}1' file
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo inet6 ::1/128 scope host valid_lft forever preferred_lft forever
2: eth2: <BROADCAST,MULTICAST,NOARP,PROMISC,UP,LOWER_UP> mtu 1600 qdisc pfifo_fast state UP qlen 1000 link/ether 08:00:27:33:58:cb brd ff:ff:ff:ff:ff:ff inet6 fe80::a00:27ff:fe33:58cb/64 scope link valid_lft forever preferred_lft forever
3: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether 08:00:27:33:58:ca brd ff:ff:ff:ff:ff:ff inet 192.168.122.10/24 brd 192.168.122.255 scope global eth0 inet6 fe80::a00:27ff:fe33:58ca/64 scope link
$awk-vrs='{gsub(/\n\s+/,“”)}1'文件
1:lo:mtu 65536 qdisc noqueue状态未知链接/环回00:00:00:00:00 brd 00:00:00:00:00:00:00:00 inet 127.0.0.1/8作用域主机lo inet 6::1/128作用域主机有效\u lft永远首选\u lft永远
2:eth2:mtu 1600 qdisc pfifo\u快速状态升级qlen 1000链路/以太08:00:27:33:58:cb brd ff:ff:ff:ff:ff:ff:ff inet6 fe80::a00:27ff:fe33:58cb/64作用域链路永久有效\u lft首选\u lft永久
3:eth0:mtu 1500 qdisc pfifo_快速状态升级qlen 1000链路/以太08:00:27:33:58:ca brd ff:ff:ff:ff:ff:ff:ff inet 192.168.122.10/24 brd 192.168.122.255作用域全局eth0 inet 6 fe80::a00:27ff:fe33:58ca/64作用域链路
sed
用于单个行上的简单替换,不适用于涉及多行的任何内容。20世纪70年代中期,
awk
发明时,所有用于跨多行操作的SED神秘结构都已过时。现在人们只把它们用于脑力练习,看看它们是否能用sed解决这个难题——实际上,你不会在代码中使用由此产生的咒语


如果您的awk不支持
\s
gawk
支持),请将
\s
更改为上面的
[:space:]

天哪,使用
awk

$ awk -v RS= '{gsub(/\n\s+/," ")}1' file
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo inet6 ::1/128 scope host valid_lft forever preferred_lft forever
2: eth2: <BROADCAST,MULTICAST,NOARP,PROMISC,UP,LOWER_UP> mtu 1600 qdisc pfifo_fast state UP qlen 1000 link/ether 08:00:27:33:58:cb brd ff:ff:ff:ff:ff:ff inet6 fe80::a00:27ff:fe33:58cb/64 scope link valid_lft forever preferred_lft forever
3: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether 08:00:27:33:58:ca brd ff:ff:ff:ff:ff:ff inet 192.168.122.10/24 brd 192.168.122.255 scope global eth0 inet6 fe80::a00:27ff:fe33:58ca/64 scope link
$awk-vrs='{gsub(/\n\s+/,“”)}1'文件
1:lo:mtu 65536 qdisc noqueue状态未知链接/环回00:00:00:00:00 brd 00:00:00:00:00:00:00:00 inet 127.0.0.1/8作用域主机lo inet 6::1/128作用域主机有效\u lft永远首选\u lft永远
2:eth2:mtu 1600 qdisc pfifo\u快速状态升级qlen 1000链路/以太08:00:27:33:58:cb brd ff:ff:ff:ff:ff:ff:ff inet6 fe80::a00:27ff:fe33:58cb/64作用域链路永久有效\u lft首选\u lft永久
3:eth0:mtu 1500 qdisc pfifo_快速状态升级qlen 1000链路/以太08:00:27:33:58:ca brd ff:ff:ff:ff:ff:ff:ff inet 192.168.122.10/24 brd 192.168.122.255作用域全局eth0 inet 6 fe80::a00:27ff:fe33:58ca/64作用域链路
sed
用于单个行上的简单替换,不适用于涉及多行的任何内容。20世纪70年代中期,
awk
发明时,所有用于跨多行操作的SED神秘结构都已过时。现在人们只把它们用于脑力练习,看看它们是否能用sed解决这个难题——实际上,你不会在代码中使用由此产生的咒语

如果您的awk不支持
\s
gawk
支持),请将
\s
更改为上面的
[:space:]

这可能对您有用(GNU-sed&Bash):

如前所述,遇到文件结尾时的
n
命令将终止sed命令,因此在尝试读取另一行之前必须检查文件结尾

此sed解决方案使用保留空间收集记录,遇到新记录或文件结尾时,将保留空间替换为模式空间,删除换行符并添加额外的分隔线

使用bash变量
$“…”
可以在一行解决方案中将sed命令分组在一起,但是另一种方法是使用
-e
标志:

sed -e '/^\S/{$h:a;x;/./{s/\n//g;p;a\ ==========' -e '};x;h;d};H;$!d;ba' file
这可能适合您(GNU-sed&Bash):

如前所述,encouteri上的
n
命令