0

I'm trying to transform ifconfig -a to give specific output but I am not sure whether sed is performing well. There is a possibility that the particular version of sed isn't performing as it should (due to different sed counterpart).

My ifconfig -a output (I only want to see the netmask):

    xennet0: flags=8863<UP,BROADCAST,NOTRAILERS,RUNNING,SIMPLEX,MULTICAST> mtu 1500
            capabilities=2800<TCP4CSUM_Tx,UDP4CSUM_Tx>
            enabled=0
            address: 0a:3d:c0:98:c6:73
            inet 172.31.11.166 netmask 0xfffff000 broadcast 172.31.15.255
            inet6 fe80::83d:c0ff:fe98:c673%xennet0 prefixlen 64 scopeid 0x1
    lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 33184
            inet 127.0.0.1 netmask 0xff000000
            inet6 ::1 prefixlen 128
            inet6 fe80::1%lo0 prefixlen 64 scopeid 0x2

Needed output (transformed output):

 0xfffff000
 0xff000000

My failed attempt:

ifconfig -a | egrep "0xf." | sed 's/inet //' | sed 's/netmask //' |
sed 's/ broadcast//' | sed 's/([0-9]{1,3}\.){3}[0-9]{1,3}//g' | sed 's/\s+//'

It gave me output as:

        172.31.11.166 0xfffff000 172.31.15.255
        127.0.0.1 0xff000000

I expected it to give my needed output.

Help will be of great assistance. I am using NetBSD 6.1.5 (Amazon EC2), however, I believe any general fixture should work.

Avineshwar
  • 51
  • 5

4 Answers4

1

With GNU grep, I'd use Perl regex with the -o option (retain only matches):

$ ifconfig -a | grep -Po '(?<=\bnetmask )\w*'
0xfffff000
0xff000000

For BSD grep, where we don't have the -P option, we can use awk or cut to get the second part only, as in

$ ifconfig -a | grep -o '\bnetmask [^ ]*' | cut -d ' ' -f 2
0xfffff000
0xff000000

If you really want to use sed, you could do this:

$ ifconfig -a | sed -n 's/.*\bnetmask \([^ ]*\).*/\1/p'
0xfffff000
0xff000000

This quite similar to Eric's answer. It suppresses output with -n, and for lines containing netmask, it extracts the word following it and prints it with (the p flag).

Benjamin W.
  • 46,058
  • 19
  • 106
  • 116
1

While doing it with sed might be interesting, I'd recommend awk as the right tool for this (and any similar) job:

ifconfig -a | awk '{ for (i = 1; i < NF; i++) {if ($i == "netmask") { print $(i+1); next; } }}'
Greg A. Woods
  • 2,663
  • 29
  • 26
  • Yes, absolutely this works, but why not just `sed -ne 's/.* netmask \([^ ]*\).*/\1/p'` ? A simple pattern match seems like way less headache than implementing an actual loop and `if` condition. (Oh, and HI GREG! :) ) – ghoti Mar 10 '16 at 03:56
  • This works, however, I am looking for minimum complexity (even if marginally different) and maximum compatibility across various Linux/Unix distros. – Avineshwar Mar 10 '16 at 04:16
  • @Avineshwar: my sed script above should be portable. Also, `ifconfig -a | awk '/netmask/{sub(/.*netmask /,"");sub(/ .*/,"");print}'` does almost the same thing in awk. Heck, `ifconfig -a | egrep -o 'netmask [^ ]+' | cut -d" " -f2` works. There's more than one way to hang a dog. In this case, there are too many to count. – ghoti Mar 10 '16 at 04:25
  • 1
    @ghoti: I really liked this one "ifconfig -a | egrep -o 'netmask [^ ]+' | cut -d" " -f2" however it won't work on Ubuntu since it is not having a string named "netmask " followed by the mask rather it has "Mask:" followed by the mask. "ifconfig -a | egrep -o 'Mask:[^ ]+' | cut -d":" -f2" this will work.Thank you, however, I think it is really not possible to find just one combination of commands that works for every distro since they're having different versions of same softwares which reduces the portability. &, "sid -ne" suggestion was minimum compatible on my tests. – Avineshwar Mar 10 '16 at 04:57
  • @ghoti, well, I always prefer something with a bit more expression in algorithmic form rather than something expressed as edit commands and regular expressions. It's more typing, but much easier typing, and far easier proof-reading (even with all the braces). Personally I would probably write C code to exactly extract all the netmask values if I were trying to solve this for myself. A list of effectively random netmask values not even tagged by interface name is a pretty stupid goal. The accepted answer of just looking for hex number is even worse. – Greg A. Woods Mar 10 '16 at 07:31
  • I agree, the goal stated in the question doesn't seem like a particularly useful one to me either. Of course, what that tells me is that this is an XY Problem, and that the solution is to a solution rather than to a problem. Such is the state of *many* StackOverflow questions, though. There is rarely enough time or attention to winnow the distractions from the actual problem before someone just posts an answer. – ghoti Mar 10 '16 at 07:43
  • 1
    @Avineshwar - `'Mask:'` is not text that shows up anywhere in the question. Why would it be included in an answer? The question was not about doing anything related to Ubuntu, or even NetBSD really, it was about how to find text that matches a certain pattern. If a goal is to produce code that will handle OTHER input data as well, it's important to include that in the question. – ghoti Mar 10 '16 at 07:46
  • BTW, I don't think `cut` is ever really a solution, or part of a solution, to any problem, and especially not if it is in a pipeline with `grep` and/or `sed`. Such patterns are clear indications that `awk` (or some equally _simple_ pattern matching algorithmic scripting language) is a better solution. – Greg A. Woods Mar 10 '16 at 09:01
  • @ghoti I totally understand your point, however, any extra information shared doesn't makes the previous information invalid and since the actual issue has already been targeted, it doesn't matter. Someone someday, instead of creating a new question might refer to this, directly. I had this thought while typing that. – Avineshwar Mar 14 '16 at 07:23
0

In some respects, you're making it too hard. And using more commands than strictly required. Here's a command line that will do what you want with only one sed(1) invocation:

ifconfig -a | sed -ne '/inet /s/^.* netmask \(.*\) broadcast.*$/\1/p'

Explanation: the "/inet /" tells sed(1) to select only lines containing that string, and then apply the rest of the expression. The rest of the expression strips out the netmask from between the keywords "netmask " and " broadcast", and prints the result.

The "-n" on the sed(1) command line tells sed(1) not to print the lines as they're examined. The "-e" says the next argument is an inline sed(1) script.

Per my comment, that misses lo*.

Changing the pattern to:

'/inet /s/^.* netmask \(0x[0-9a-fA-F]*\).*$/\1/p'

creates the desired results. (including all interfaces running inet, including lo*)

0

Use Grep with Extended Regular Expressions

You can use grep's ERE engine and the --only-matching flag to extract just the hex values. To do this, use egrep or grep -E to turn on extended regular expressions. For example:

$ egrep -o '0x[[:xdigit:]]{8}' /tmp/corpus 
0xfffff000
0xff000000

Likewise, you can also pipe in output and get the same results with:

$ ifconfig -a | egrep -o '0x[[:xdigit:]]{8}'

This works with both GNU and BSD greps, and doesn't rely on the PCRE library. It should therefore work on most modern systems without the need to tweak anything.

Todd A. Jacobs
  • 81,402
  • 15
  • 141
  • 199
  • I would tend to avoid this solution for anything but the most trivial one-time manual command-line test since it will output any matching hexadecimal number. – Greg A. Woods Mar 10 '16 at 03:51