将 pcregrep 翻译成 Perl 一行
我需要找到新 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 "$1";};}'
如果我在同一行中使用积极的前瞻搜索,则它正在工作;例如:
ifconfig | perl -pe 'while (<>) {if (/^([^\t:]+)(?=:([^\n]|\n\t)*mtu 1380)/){print "$1";};}'
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
I am on macOS Monterey, zsh and perl 5.34
谢谢你的帮助
marek
I need to find all active network interfaces on new macOS. That means the following one-liner with pcregrep
will not work:
ifconfig | pcregrep -M -o '^[^\t:]+(?=:([^\n]|\n\t)*status: active)'
because pcregrep
is no default install on macOS.
I tried to translate it into egrep
to no avail, because a positive lookahead is not possible, right?
So I tried with a one-liner in perl. But the following command is not working, because the switch -pe
is not gobbling up all lines together. I tried with -p0e
too.
ifconfig | perl -pe 'while (<>) {if (/^[^\t:]+(?=:([^\n]|\n\t)*status: active)/){print "$1";};}'
If I search with a positive lookahead the same line, it is working; for example:
ifconfig | perl -pe 'while (<>) {if (/^([^\t:]+)(?=:([^\n]|\n\t)*mtu 1380)/){print "$1";};}'
utun0
A typical output of 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
The expected result would be:
en10
I am on macOS Monterey, zsh and perl 5.34
Thank you for your help
marek
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
由于
ifconfig
的输出通常† 对于每个接口都有一个多行文本块,所有文本块均由空行分隔,因此可以方便地分段阅读(-00)。然后剩下的就简化了很多我们仍然需要
/s
修饰符,使.
也匹配换行符,因为每个段落本身是一个多行字符串,并且模式需要匹配跨越多条线路。† 除了在用于此问题的 MacOS 上没有之外,没有空行分隔接口块。那么寻找段落就没有意义了(换行符不是换行符),并且这个答案不适用于该系统。
这是一种经典的逐行方法,它在该接口的输出的第一行设置接口名称(行开头没有空格),然后测试活动状态
这允许接口名称内有空格,什么是不太可能(甚至可能不允许)。对于限制性更强的模式(名称中不允许有空格),请使用
/^(\S+?)\s*:/
(或更高效的/^([^: \s]+)/
)。\s*
和前面的?
只是为了使其不捕获尾随空格(就在:
之前)(如果可能的话) 。这也适用于接口块之间有空行的情况。
Since output of
ifconfig
normally† has a multiline block of text for each interface, all separated by blank lines, it is convenient to read it in paragraphs (-00). Then the rest simplifies a lotWe still need the
/s
modifier, making.
match a newline as well, as each paragraph itself is a multiline string and the pattern needs to match across multiple lines.† Except that it doesn't on the MacOS used for this question -- there are no blank lines separating blocks for interfaces. Then there is no point in seeking paragraphs (breaking on newline which isn't) and this answer doesn't work for that system.
Here is then a classic line-by-line approach that does -- set the interface name at the first line for that interface's output (no spaces at line beginning), then test for active status
This allows spaces inside an interface name, what is very unlikely (and perhaps not even allowed). For a more restrictive pattern, which doesn't allow spaces in the name, use
/^(\S+?)\s*:/
(or the more efficient/^([^:\s]+)/
). The\s*
and the preceding?
are there only to make it not capture the trailing spaces (right before:
), if any were possible.This works in the case when there are empty lines between interface blocks as well.
您可以使用
正则表达式测试。
在这里,
-0777
提取文件,以便正则表达式可以匹配多行文本范围(M
等效项将换行符暴露给 pcregrep 中的模式),say "$&"
打印所有匹配的子字符串(o
等效项,另请参阅g
标志)。我编辑了
[^\t:]+
以匹配除制表符、冒号以及 CR/LF 字符之外的任何一个或多个字符。另外,我将([^\n]|\n\t)*
替换为更高效的(?:.*\R\t)*
,它匹配零或除换行符之外的任何零个或多个字符的多次出现,直到行尾 (.*
),然后是换行符序列 (\R
),然后制表符 (\t
)。另外,请注意
m
标志以使^
锚点也匹配任何行起始位置。You can use
See the regex test.
Here,
-0777
slurps the file so that a regex could match multiline text spans (theM
equivalent that exposes the newlines to the pattern in pcregrep),say "$&"
prints all matched substrings (theo
equivalent, also seeg
flag).I edited the
[^\t:]+
to match any one or more chars other than tabs, colons and also CR/LF chars. Also, I replaced([^\n]|\n\t)*
into a more efficient(?:.*\R\t)*
that matches zero or more occurrences of any zero or more chars other than line break chars till the end of a line (.*
), then a line break sequence (\R
), and then a tab char (\t
).Also, note the
m
flag to make^
anchor also match any line start position.perl 的 -n 和 -p 命令行开关在 -e 代码周围添加隐式 while (<>) {...} 块,此外 -p 在每次迭代结束时打印该行。所以你需要将 -p 更改为 -n 并只打印出匹配的行;并删除多余的和不需要的 while 循环。所以像
perl's -n and -p command-line switches add an implicit while (<>) {...} block around the -e code, and in addition -p prints the line at the end of each iteration. So you need to change the -p to -n and only print out the lines which match; and remove the extra and unneeded while loop. So something like