将 pcregrep 翻译成 Perl 一行代码
translate pcregrep into Perl one-liner
我需要在新的 macOS 上找到所有活动的网络接口。这意味着以下带有 pcregrep
的单行代码将不起作用:
ifconfig | pcregrep -M -o '^[^\t:]+(?=:([^\n]|\n\t)*status: active)'
因为 pcregrep
在 macOS 上没有默认安装。
我试图将其翻译成 egrep
但无济于事,因为不可能进行正面的前瞻,对吗?
所以我尝试在 perl 中使用单行代码。但是下面的命令不起作用,因为开关 -pe
没有同时吞噬所有行。我也试过 -p0e
。
ifconfig | perl -pe 'while (<>) {if (/^[^\t:]+(?=:([^\n]|\n\t)*status: active)/){print "";};}'
如果我在同一行中使用正面前瞻搜索,它就可以工作;例如:
ifconfig | perl -pe 'while (<>) {if (/^([^\t:]+)(?=:([^\n]|\n\t)*mtu 1380)/){print "";};}'
utun0
ifconfig
的典型输出:
en10: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
options=6467<RXCSUM,TXCSUM,VLAN_MTU,TSO4,TSO6,CHANNEL_IO,PARTIAL_CSUM,ZEROINVERT_CSUM>
ether 00:e0:4c:68:01:20
inet6 fe80::1470:31b9:a01c:6f5e%en10 prefixlen 64 secured scopeid 0xd
inet 192.168.178.39 netmask 0xffffff00 broadcast 192.168.178.255
inet6 2003:ee:4f1a:ce00:864:f90c:9a11:6ad9 prefixlen 64 autoconf secured
inet6 2003:ee:4f1a:ce00:d89a:7e34:6dd4:1370 prefixlen 64 autoconf temporary
nd6 options=201<PERFORMNUD,DAD>
media: autoselect (1000baseT <full-duplex>)
status: active
预期结果为:
en10
我在 macOS Monterey、zsh 和 perl 5.34
感谢您的帮助
马雷克
perl 的 -n 和 -p command-line 开关在 -e 代码周围添加一个隐式的 while (<>) {...} 块,另外 -p 在每个代码的末尾打印行迭代。因此,您需要将 -p 更改为 -n 并仅打印出匹配的行;并删除多余的和不需要的 while 循环。所以像
ifconfig | perl -ne 'print if /...../'
你可以使用
perl -0777 -nE 'say "$&" while /^[^\n\r\t:]+(?=:(?:.*\R\t)*status:\h+active)/gm'
参见regex test。
这里,-0777
slurps 文件,以便正则表达式可以匹配多行文本跨度(M
等效项将换行符暴露给 pcregrep[=36= 中的模式]), say "$&"
打印所有匹配的子字符串(o
等效项,另请参阅 g
标志)。
我编辑了 [^\t:]+
以匹配制表符、冒号和 CR/LF 字符以外的任何一个或多个字符。此外,我将 ([^\n]|\n\t)*
替换为更高效的 (?:.*\R\t)*
,它匹配除换行字符以外的任何零个或多个字符的零次或多次出现,直到行尾 (.*
),然后一个换行符序列 (\R
),然后是一个制表符 (\t
).
此外,请注意 m
标志,使 ^
锚点也匹配任何行的起始位置。
由于ifconfig
正常输出†每个界面多行文本块,全部用空行分隔,方便分段阅读( -00)。那么剩下的就简单很多
ifconfig -a | perl -00 -nE'say if /^(.+?)\s*:.*?status:\s+active/s'
我们仍然需要 /s
修饰符,使 .
也匹配换行符,因为每个段落本身都是多行字符串,模式需要跨多行匹配。
† 除了它不在用于此问题的 MacOS 上——没有空行分隔接口块。那么寻找段落是没有意义的(在换行符上换行不是)并且这个答案不适用于该系统。
这是一个经典的 line-by-line 方法——在该接口输出的第一行设置接口名称(行首没有空格),然后测试活动状态
perl -wnE'$ifn=, next if /^(\S[^:]+?)\s*:/; say $ifn if /status:\s+active/' file
这允许在接口名称中使用空格,这是不太可能的(甚至可能不允许)。对于不允许在名称中使用空格的更严格的模式,请使用 /^(\S+?)\s*:/
(或更有效的 /^([^:\s]+)/
)。 \s*
和前面的 ?
只是为了让它不捕获尾随空格(就在 :
之前),如果可能的话。
这也适用于界面块之间有空行的情况。
我需要在新的 macOS 上找到所有活动的网络接口。这意味着以下带有 pcregrep
的单行代码将不起作用:
ifconfig | pcregrep -M -o '^[^\t:]+(?=:([^\n]|\n\t)*status: active)'
因为 pcregrep
在 macOS 上没有默认安装。
我试图将其翻译成 egrep
但无济于事,因为不可能进行正面的前瞻,对吗?
所以我尝试在 perl 中使用单行代码。但是下面的命令不起作用,因为开关 -pe
没有同时吞噬所有行。我也试过 -p0e
。
ifconfig | perl -pe 'while (<>) {if (/^[^\t:]+(?=:([^\n]|\n\t)*status: active)/){print "";};}'
如果我在同一行中使用正面前瞻搜索,它就可以工作;例如:
ifconfig | perl -pe 'while (<>) {if (/^([^\t:]+)(?=:([^\n]|\n\t)*mtu 1380)/){print "";};}'
utun0
ifconfig
的典型输出:
en10: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
options=6467<RXCSUM,TXCSUM,VLAN_MTU,TSO4,TSO6,CHANNEL_IO,PARTIAL_CSUM,ZEROINVERT_CSUM>
ether 00:e0:4c:68:01:20
inet6 fe80::1470:31b9:a01c:6f5e%en10 prefixlen 64 secured scopeid 0xd
inet 192.168.178.39 netmask 0xffffff00 broadcast 192.168.178.255
inet6 2003:ee:4f1a:ce00:864:f90c:9a11:6ad9 prefixlen 64 autoconf secured
inet6 2003:ee:4f1a:ce00:d89a:7e34:6dd4:1370 prefixlen 64 autoconf temporary
nd6 options=201<PERFORMNUD,DAD>
media: autoselect (1000baseT <full-duplex>)
status: active
预期结果为:
en10
我在 macOS Monterey、zsh 和 perl 5.34
感谢您的帮助
马雷克
perl 的 -n 和 -p command-line 开关在 -e 代码周围添加一个隐式的 while (<>) {...} 块,另外 -p 在每个代码的末尾打印行迭代。因此,您需要将 -p 更改为 -n 并仅打印出匹配的行;并删除多余的和不需要的 while 循环。所以像
ifconfig | perl -ne 'print if /...../'
你可以使用
perl -0777 -nE 'say "$&" while /^[^\n\r\t:]+(?=:(?:.*\R\t)*status:\h+active)/gm'
参见regex test。
这里,-0777
slurps 文件,以便正则表达式可以匹配多行文本跨度(M
等效项将换行符暴露给 pcregrep[=36= 中的模式]), say "$&"
打印所有匹配的子字符串(o
等效项,另请参阅 g
标志)。
我编辑了 [^\t:]+
以匹配制表符、冒号和 CR/LF 字符以外的任何一个或多个字符。此外,我将 ([^\n]|\n\t)*
替换为更高效的 (?:.*\R\t)*
,它匹配除换行字符以外的任何零个或多个字符的零次或多次出现,直到行尾 (.*
),然后一个换行符序列 (\R
),然后是一个制表符 (\t
).
此外,请注意 m
标志,使 ^
锚点也匹配任何行的起始位置。
由于ifconfig
正常输出†每个界面多行文本块,全部用空行分隔,方便分段阅读( -00)。那么剩下的就简单很多
ifconfig -a | perl -00 -nE'say if /^(.+?)\s*:.*?status:\s+active/s'
我们仍然需要 /s
修饰符,使 .
也匹配换行符,因为每个段落本身都是多行字符串,模式需要跨多行匹配。
† 除了它不在用于此问题的 MacOS 上——没有空行分隔接口块。那么寻找段落是没有意义的(在换行符上换行不是)并且这个答案不适用于该系统。
这是一个经典的 line-by-line 方法——在该接口输出的第一行设置接口名称(行首没有空格),然后测试活动状态
perl -wnE'$ifn=, next if /^(\S[^:]+?)\s*:/; say $ifn if /status:\s+active/' file
这允许在接口名称中使用空格,这是不太可能的(甚至可能不允许)。对于不允许在名称中使用空格的更严格的模式,请使用 /^(\S+?)\s*:/
(或更有效的 /^([^:\s]+)/
)。 \s*
和前面的 ?
只是为了让它不捕获尾随空格(就在 :
之前),如果可能的话。
这也适用于界面块之间有空行的情况。