Home > database >  translate pcregrep into Perl one-liner
translate pcregrep into Perl one-liner

Time:03-28

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

CodePudding user response:

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 /...../'

CodePudding user response:

You can use

perl -0777 -nE 'say "$&" 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.

CodePudding user response:

Given that output of ifconfig normally has a multiline block of text for each interface, separated by a blank line, 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'
  • Related