Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Am I thinking in Bash still?

48 views
Skip to first unread message

T

unread,
Aug 1, 2015, 2:18:53 AM8/1/15
to
Hi All,

This is the result of the command:

$ ip -f inet addr show br0

4: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue
state UNKNOWN
inet 192.168.255.10/24 brd 192.168.255.255 scope global br0


In bash, I would extract the network and mask with

$ ip -f inet addr show br0 | grep inet | awk {'print $2}' | awk
-F "/" '{print $1}'

192.168.255.10

$ ip -f inet addr show br0 | grep inet | awk {'print $2}' | awk -F
"/" '{print $2}'
24


This is what I did in Perl.

$ more ip.extract.pl
<code>
#!/usr/bin/perl

use strict;
use warnings;

my $Sysip=qx(ip -f inet addr show br0);
my $Start=index($Sysip, "inet ") + 5;
my $Stop=index($Sysip, " ", $Start);

my $Length= $Stop - $Start;
my $IpMask=substr $Sysip, $Start, $Length;

my ($ip, $mask) = split ('/', $IpMask);

print "ip = $ip\nmask = $mask\n";
<code>


I realize that I could have written
my $IpMask=substr $Sysip, $Start, $Length;
as
my $IpMask=substr $Sysip, $Start, $Stop - $Start;

But it is obvious what I am doing if I use $Length.

I also could have put $Start and $Stop into the
"substr", but that would have been an eyeful to
maintain later.

And I dropped the grep (Perl has one) as only one line
had "addr " on it.

Am I still thinking in Bash, or am I starting to transition?

Many thanks,
-T

Jens Thoms Toerring

unread,
Aug 1, 2015, 4:08:43 AM8/1/15
to
Perhaps a bit since with Perl you start to look for regular
expressions in such cases once you've got the hang of them -
they tend to be simpler than taking strings apart the way
you've done it (but that might be a case of "If I have such
a nice hammer everything should be a nail";-) So my first
idea would be something along the lines of

qx(ip -f inet addr show br0) =~ /inet\s+((\d+\.){3}\d+)\/(\d+)\s+brd/;
print "$1\n$3\n";

But then what's the best solution depends a lot on the
circumstances and in Perl there is always more than one
way to do it.
Regards, Jens
--
\ Jens Thoms Toerring ___ j...@toerring.de
\__________________________ http://toerring.de

C.DeRykus

unread,
Aug 1, 2015, 4:22:28 AM8/1/15
to
TIMTOWTDI but I'd make it more perl-ish to keep up with the shorter, awk-ish looking one:

ip -f inet ... | perl -n0777 -E 'say $1 if m{inet.*/(\d+)}'


--
Charles DeRykus

T

unread,
Aug 1, 2015, 4:48:10 AM8/1/15
to
Hi Jens,

I am going to have to read over that line really closely.

Thank you for the feedback!

-T

T

unread,
Aug 1, 2015, 4:50:22 AM8/1/15
to
Thank you. I am going to have to read over that really slowly!

What is the -n0777? What is the d+?

Jens Thoms Toerring

unread,
Aug 1, 2015, 5:50:21 AM8/1/15
to
T <T...@invalid.invalid> wrote:
> On 08/01/2015 01:08 AM, Jens Thoms Toerring wrote:
> > qx(ip -f inet addr show br0) =~ /inet\s+((\d+\.){3}\d+)\/(\d+)\s+brd/;
> > print "$1\n$3\n";
> >
> I am going to have to read over that line really closely.

It's often relatively simple when you put it into words:
what you want is 4 times a bunch of digits with dots in
between, then a slash and again a bunch of digits. All
this must be surrounded by 'inet ' and ' br0'. Expressed
in terms of a regex you thus have

/inet\s+ # 'inet' and (one or more) white-spaces
((\d+\.){3}\d+) # 3 sets of digits with dots + another set of digits
\/ # a slash
(\d+) # another set of digits
\s+brd/x; # finally white-space(s) and 'brd'

The parts you're interested in are enclosed in parentheses
and thus can be later refered to as $1, $2, $3 - of interest
are $1 (what's in the first set of parentheses) and $3 (the
stuff in the third pair of parantheses).

The regex for the IP address is a bit "loose" since it
will also capture things that can't be IP addresses
(like '5821.337.1.0') but that's probably no problem
here where you know what the input is going to be -
and a regex that only matches IP addresses would tend
to be a bit more lengthy (but that going to get better
with IPv6 addresses;-)

Note that you can split the regex apart like that and add
comments if you use the 'x' flag at the end - that can
help quite a bit understanding what you were thinking when
you later have to modify your script;-)

T

unread,
Aug 1, 2015, 5:59:25 AM8/1/15
to
My brain hurts! I will have to read it over very, very slowly!

Thank you for helping me with this!

-T

Wasell

unread,
Aug 1, 2015, 6:02:23 AM8/1/15
to
On Fri, 31 Jul 2015 23:18:50 -0700, in article <mpho9b$1vg$1...@dont-email.me>, T
wrote:
>
> Hi All,
>
> This is the result of the command:
>
> $ ip -f inet addr show br0
>
> 4: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue
> state UNKNOWN
> inet 192.168.255.10/24 brd 192.168.255.255 scope global br0
[...]
> This is what I did in Perl.
>
> $ more ip.extract.pl
> <code>
> #!/usr/bin/perl
>
> use strict;
> use warnings;
>
> my $Sysip=qx(ip -f inet addr show br0);
> my $Start=index($Sysip, "inet ") + 5;
> my $Stop=index($Sysip, " ", $Start);
>
> my $Length= $Stop - $Start;
> my $IpMask=substr $Sysip, $Start, $Length;
>
> my ($ip, $mask) = split ('/', $IpMask);
>
> print "ip = $ip\nmask = $mask\n";
> <code>

Simple rule for extracting stuff from strings:

* Use split when you know what you want to throw away; use regexps when
you know what you want to keep; use substr and index almost never.

I would have done thusly:
<code>
#!/usr/bin/perl

use strict;
use warnings;

my $sysip = qx( ip -f inet addr show br0 ) or die "couldn't run ip";
my ($ip, $mask) = $sysip =~ m!^inet\s+([^/]+)/(\S+)!m or die 'no match';

print "ip: $ip\nmask: $mask\n";
</code>

T

unread,
Aug 1, 2015, 6:03:25 AM8/1/15
to
Thank you!

T

unread,
Aug 1, 2015, 6:06:21 AM8/1/15
to
On 08/01/2015 03:02 AM, Wasell wrote:
What the hell?

m!^inet\s+([^/]+)/(\S+)!m

Can you explain?

C.DeRykus

unread,
Aug 1, 2015, 6:07:10 AM8/1/15
to
See: perldoc perlrun
...
Command Switches
...
-0[octal/hexadecimal]

The special value 00 will cause Perl to slurp files in paragraph
mode. Any value 0400 or above will cause Perl to slurp files
whole, but by convention the value 0777 is the one normally used
for this purpose.
-n causes Perl to assume the following loop around your program,
which makes it iterate over filename arguments somewhat like sed
-n or awk:
....


See: perldoc perlrequick (Extracting Matches)

--
Charles DeRykus

Jens Thoms Toerring

unread,
Aug 1, 2015, 6:36:29 AM8/1/15
to
Another way to skin the cat with a regex

m!^inet\s+ # line starting with 'inet' and white-space
([^/]+) # everything that's not a slash (but at least one char)
/ # a slash
(\S+)!mx # everything that's not a white-space (at least one char)x

You can enclose a regex in all kinds of characters, Wasell
picked an exclamation mark here.

Within '[]' you list the characters you want - or, if you
start it off with a '^', the characters you don't want. So
'^/]' says: match any character that's not a slash.
a
And the matching stops, due to the '\S+' bit ath the
space before 'brd'.
Regards, Jensxs

shar...@hotmail.com

unread,
Aug 1, 2015, 6:47:24 AM8/1/15
to
On Saturday, 1 August 2015 11:48:53 UTC+5:30, T wrote:
[snip]
>
> Am I still thinking in Bash, or am I starting to transition?
>

I am sure you must be thinking, whew it's such hard work in perl,
bash was much better. Aww goodness me , why'd I trick myself into
doing this perl thing....

But the fact that you are starting to build something using things from
the Perl toolbox (substr/index/regex/etc.) means you are on the right path.

>
> In bash, I would extract the network and mask with
>
> $ ip -f inet addr show br0 | grep inet | awk {'print $2}' | awk
> -F "/" '{print $1}'
>
> 192.168.255.10
>
> $ ip -f inet addr show br0 | grep inet | awk {'print $2}' | awk -F
> "/" '{print $2}'
> 24
>

You could do both the determinations, like as,

$ ip -f .... | perl -lne 'print for m|\s inet \s ([^/]+)/(\d+) \s|gx'

Rainer Weikusat

unread,
Aug 1, 2015, 8:08:17 AM8/1/15
to
T <T...@invalid.invalid> writes:
> This is the result of the command:
>
> $ ip -f inet addr show br0
>
> 4: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue
> state UNKNOWN
> inet 192.168.255.10/24 brd 192.168.255.255 scope global br0
>
>
> In bash, I would extract the network and mask with
>
> $ ip -f inet addr show br0 | grep inet | awk {'print $2}' | awk
> -F "/" '{print $1}'


Sometimes, it's a good idea to have a closer look at the tools one
happens to be using before settling on a way how to make them behave.

[rw@doppelsaurus]~#ip -o -f inet addr show eth0
2: eth0 inet 192.168.1.5/24 brd 192.168.1.255 scope global eth0

What you want is two sequences of non-whitespace characters separated by
/. Since / occurs only as separator between the two components of the
address, it can be used to 'anchor' a regex extracting them. Eg,

ip -o -f inet addr show eth0 | perl -ne '($a, $m) = /(\S+)\/(\S+)/; print "addr $a, mask $m\n";'

\S+ matches a sequence of non-whitespace characters. Putting this in ()
means 'capture the value and return it' here, hence

($a, $m) = /(\S+)\/(\S+)/

extracts the two wanted sequences out of the input line (in $_) and
assigns them to $a and $m.

Michal Jaegermann

unread,
Aug 3, 2015, 2:16:36 PM8/3/15
to
On Fri, 31 Jul 2015 23:18:50 -0700, T wrote:


> In bash, I would extract the network and mask with
>
> $ ip -f inet addr show br0 | grep inet | awk {'print $2}' | awk
> -F "/" '{print $1}'
>
> 192.168.255.10
>
> $ ip -f inet addr show br0 | grep inet | awk {'print $2}' | awk -F
> "/" '{print $2}'
> 24
>

No, you are not really thinking in bash. If you would you would write
your extraction, for example, like that:

$ ip -o -f inet addr show br0 | \
while read a b c d rest ; do echo -e ${d/\//\\n} ; done

OTOH if you would really like to use awk as a filter one of reasonable
ways to do it could look like this:

$ ip -f inet addr show br0 | \
awk '/inet/{sub("/", " "); print $2; print $3}'

Of course you could process your output in a desired manner as well
through one-liners in sed, or perl, or python, or ruby, or ...

Michal

T

unread,
Aug 4, 2015, 12:49:28 AM8/4/15
to
I am not sure why slurping matter, but that will probably
be something I learn when I start manipulating files.

Thank you for the help!


T

unread,
Aug 4, 2015, 12:56:27 AM8/4/15
to
On 08/01/2015 03:47 AM, shar...@hotmail.com wrote:
> On Saturday, 1 August 2015 11:48:53 UTC+5:30, T wrote:
> [snip]
>>
>> Am I still thinking in Bash, or am I starting to transition?
>>
>
> I am sure you must be thinking, whew it's such hard work in perl,
> bash was much better. Aww goodness me , why'd I trick myself into
> doing this perl thing....

Hi Sharma,

To me Bash is like programming with one hand tied behind my back.
(Windows batch would be one hand tied behind my back on the other
hand broken.)

>
> But the fact that you are starting to build something using things from
> the Perl toolbox (substr/index/regex/etc.) means you are on the right path.
>
>>
>> In bash, I would extract the network and mask with
>>
>> $ ip -f inet addr show br0 | grep inet | awk {'print $2}' | awk
>> -F "/" '{print $1}'
>>
>> 192.168.255.10
>>
>> $ ip -f inet addr show br0 | grep inet | awk {'print $2}' | awk -F
>> "/" '{print $2}'
>> 24
>>
>
> You could do both the determinations, like as,
>
> $ ip -f .... | perl -lne 'print for m|\s inet \s ([^/]+)/(\d+) \s|gx'
>

The big criticism I see so far of Perl is that it is a
"write only language". I try to write so I can easily figure
our what I am doing. There is a lot of temptation to put
the sun, the moon, and the stars all into one line.

I purposefully take several lines to do what can be crammed
into one so I can figure it out later.

Thank you for the example: that is the way I learn best!
I will keep this and read it over slowly.

-T

Funny, I am writing a module where I copied bash script into
it and converted it over to Perl. Didn't get it all and Perl
shook the finger at me pretty hard. I cracked up a bit.
0 new messages