想要sed魔法:
我想知道如何在不立即打印的情况下保存/记住行中的匹配项(如标题部分)
并仅在下一行某处找到其他匹配项时打印它,
但是已保存/记住的标题部分只应打印一次,以用于该标题下任意数量的其他后续匹配项
,如果在记住的标题行下方的任何后续行中没有其他内容匹配,则根本不应该打印该文件
例如ifconfig
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
options=1203<RXCSUM,TXCSUM,TXSTATUS,SW_TIMESTAMP>
inet 127.0.0.1 netmask 0xff000000
inet6 ::1 prefixlen 128
inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1
inet 127.94.0.2 netmask 0xff000000
inet 127.94.0.1 netmask 0xff000000
nd6 options=201<PERFORMNUD,DAD>
gif0: flags=8010<POINTOPOINT,MULTICAST> mtu 1280
stf0: flags=0<> mtu 1280
XHC20: flags=0<> mtu 0
en3: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
options=10b<RXCSUM,TXCSUM,VLAN_HWTAGGING,AV>
ether 68:5b:35:c1:b3:91
inet6 fe80::8ef:5953:53b:7058%en3 prefixlen 64 secured scopeid 0x5
inet 192.168.0.2 netmask 0xffffff00 broadcast 192.168.0.255
inet6 2a02:810d:9c0:59bb:c0d:c8af:7e27:42f1 prefixlen 64 autoconf secured
inet6 2a02:810d:9c0:59bb:643f:a2cb:ac5f:7c71 prefixlen 64 autoconf temporary
nd6 options=201<PERFORMNUD,DAD>
media: autoselect (1000baseT <full-duplex,flow-control,energy-efficient-ethernet>)
status: active
en0: flags=8823<UP,BROADCAST,SMART,SIMPLEX,MULTICAST> mtu 1500
ether 6c:40:08:9c:45:ce
nd6 options=201<PERFORMNUD,DAD>
media: autoselect (<unknown type>)
status: inactive
与ifconfig | gsed -n -E '/^[a-z0-9]*:/h; /\tinet (addr:)?[0-9.a-fA-F:]*/{x;p;x;p}'
我得到了(已经很棒了,但是还不不错):
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
inet 127.0.0.1 netmask 0xff000000
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
inet 127.94.0.2 netmask 0xff000000
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
inet 127.94.0.1 netmask 0xff000000
en3: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
inet 192.168.0.2 netmask 0xffffff00 broadcast 192.168.0.255
但是我只想为其所有ip获取一次报头(并且不会混乱)
lo0:
inet 127.0.0.1
inet 127.94.0.2
inet 127.94.0.1
en3:
inet 192.168.0.2
答案 0 :(得分:2)
请您尝试一次。
Your_command | awk '
/^[a-zA-Z]+/{
count=""
val=$1
next
}
val && match($0,/.*[0-9]+\.[-0-9]+\.[0-9]+\.[0-9]+ +/){
if(++count==1){
print val
}
value=substr($0,RSTART,RLENGTH)
sub(/ +$/,"",value)
print value
value=""
}
'
答案 1 :(得分:1)
所以我想通了昨晚的操作方法:)
ifconfig | gsed -n -E '
/^[a-z0-9]*:/ { # for lines starting with this
s/^([a-z0-9]*:).*/\1/;h # extract the start and put it into hold space
}
/\tinet (addr:)?[0-9.a-fA-F:]*/ { # for lines containing this
s/^.*(\tinet (addr:)?[0-9.a-fA-F:]*).*/\1/ # extract it
x # swap hold space and pattern space
G # and then append the hold space (former pattern space) to it
s/^\n// # replace leading \n if former hold space was empty
p # print the concatenated former hold space and modified pattern space
s/^.*$// # empty the pattern space
x # swap the now empty pattern space to hold space
}
'
或(或多或少)单线:
ifconfig | gsed -n -E '
/^[a-z0-9]*:/ { s/^([a-z0-9]*:).*/\1/;h };
/\tinet (addr:)?[0-9.a-fA-F:]*/ { s/^.*(\tinet (addr:)?[0-9.a-fA-F:]*).*/\1/;x;G;s/^\n//;p;s/^.*$//;x}'
给我希望的
lo0:
inet 127.0.0.1
inet 127.94.0.2
inet 127.94.0.1
en3:
inet 192.168.0.2
答案 2 :(得分:1)
我为您提供两个建议:
例如:
parse.sed
/^[^ ]+/ { # For lines starting with non-space
x # \
/\n/p # Did we collect any IP addresses?
x # /
s/ .*// # Clean up interface name
h # Overwrite hold-space
}
/inet / {
s/ netmask.*//
H # Collect ip addresses in hold-space
}
$ {
x # Print the last interface if
/\n/p # it contained IP addresses
}
像这样运行它:
ifconfig | gsed -nEf parse.sed
输出:
lo0:
inet 127.0.0.1
inet 127.94.0.2
inet 127.94.0.1
en3:
inet 192.168.0.2
答案 3 :(得分:0)
sed用于执行简单的s/old/new
,仅此,对于其他任何操作,只需使用awk:
$ ifconfig | awk '/^[[:alpha:]]/{hdr=$1 ORS} $1=="inet"{print hdr " " $1, $2; hdr=""}'
lo0:
inet 127.0.0.1
inet 127.94.0.2
inet 127.94.0.1
en3:
inet 192.168.0.2
答案 4 :(得分:0)
这可能对您有用(GNU sed):
sed -En '/^\S/h;s/^(\s+inet\s+\S+).*/\1/;T;x;s/\s.*//p;x;p' file
将标题行存储在保留空间中。
删除包含inet
的行的IP地址之后的所有内容。
如果替换不成功,请保释。否则,请返回到保留空间并尝试删除标题行的末尾并进行打印。
返回到模式空间并打印原始IP地址行。
标头仅打印一次,因为一旦行已编辑,替换将失败。