将 pcregrep 翻译成 Perl 一行

发布于 2025-01-17 05:38:06 字数 1451 浏览 3 评论 0原文

我需要找到新 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

烟织青萝梦 2025-01-24 05:38:06

由于 ifconfig 的输出通常 对于每个接口都有一个多行文本块,所有文本块均由空行分隔,因此可以方便地分段阅读(-00)。然后剩下的就简化了很多

ifconfig -a | perl -00 -nE'say $1 if /^(.+?)\s*:.*?status:\s+active/s'

我们仍然需要 /s 修饰符,使 . 也匹配换行符,因为每个段落本身是一个多行字符串,并且模式需要匹配跨越多条线路。


除了在用于此问题的 MacOS 上没有之外,没有空行分隔接口块。那么寻找段落就没有意义了(换行符不是换行符),并且这个答案不适用于该系统。

这是一种经典的逐行方法,它在该接口的输出的第一行设置接口名称(行开头没有空格),然后测试活动状态

perl -wnE'$ifn=$1, next if /^(\S[^:]+?)\s*:/; say $ifn if /status:\s+active/' file

这允许接口名称内有空格,什么是不太可能(甚至可能不允许)。对于限制性更强的模式(名称中不允许有空格),请使用 /^(\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 lot

ifconfig -a | perl -00 -nE'say $1 if /^(.+?)\s*:.*?status:\s+active/s'

We 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

perl -wnE'$ifn=$1, next if /^(\S[^:]+?)\s*:/; say $ifn if /status:\s+active/' file

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.

欢烬 2025-01-24 05:38:06

您可以使用

perl -0777 -nE 'say "
amp;" while /^[^\n\r\t:]+(?=:(?:.*\R\t)*status:\h+active)/gm'

正则表达式测试

在这里,-0777 提取文件,以便正则表达式可以匹配多行文本范围(M 等效项将换行符暴露给 pcregrep 中的模式),say "$&" 打印所有匹配的子字符串(o 等效项,另请参阅 g 标志)。

我编辑了 [^\t:]+ 以匹配除制表符、冒号以及 CR/LF 字符之外的任何一个或多个字符。另外,我将 ([^\n]|\n\t)* 替换为更高效的 (?:.*\R\t)* ,它匹配零或除换行符之外的任何零个或多个字符的多次出现,直到行尾 (.*),然后是换行符序列 (\R),然后制表符 (\t)。

另外,请注意 m 标志以使 ^ 锚点也匹配任何行起始位置。

You can use

perl -0777 -nE 'say "
amp;" while /^[^\n\r\t:]+(?=:(?:.*\R\t)*status:\h+active)/gm'

See the regex test.

Here, -0777 slurps the file so that a regex could match multiline text spans (the M equivalent that exposes the newlines to the pattern in pcregrep), say "$&" prints all matched substrings (the o equivalent, also see g 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.

薄荷梦 2025-01-24 05:38:06

perl 的 -n 和 -p 命令行开关在 -e 代码周围添加隐式 while (<>) {...} 块,此外 -p 在每次迭代结束时打印该行。所以你需要将 -p 更改为 -n 并只打印出匹配的行;并删除多余的和不需要的 while 循环。所以像

ifconfig | perl -ne 'print if /...../'

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

ifconfig | perl -ne 'print if /...../'
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文