Skip to content
Advertisement

parsing ethtool command output using sed and awk

I am working on a shell script to parse the advertised mode and supported mode from the ethtool command and match them against an expected value. The idea is both expected and supported modes should have a common value to pass the condition.

Data:

# ethtool eth5                                                                                                                                                                          
Settings for eth1:                                                                                                                                                                                                       
        Supported ports: [ Backplane ]                                                                                                                                                                                   
        Supported link modes:   1000baseKX/Full                                                                                                                                                                          
                                10000baseKR/Full                                                                                                                                                                         
                                15000baseKR/Full                                                                                                                                                                         
        Supported pause frame use: Symmetric                                                                                                                                                                             
        Supports auto-negotiation: Yes                                                                                                                                                                                   
        Supported FEC modes: None BaseR RS                                                                                                                                                                               
        Advertised link modes:  1000baseKX/Full                                                                                                                                                                          
                                10000baseKR/Full                                                                                                                                                                         
                                15000baseKR/Full

I have currently used the below for the same.

link_mode_expected=15000baseKR

# get the mode using the shell command and parse the value needed
mode_supported=`ethtool ${eth_device} | sed -ne '/Supported link modes:/,/:/p' |
sed  -e 's/^[[:space:]]*//'  -e 's/[[:space:]]*$//' | grep "$link_mode_expected"`
mode_advertised=`ethtool ${eth_device} | sed -ne '/Advertised link modes:/,/:/p' |
sed -e 's/^[[:space:]]*//'  -e 's/[[:space:]]*$//' | grep "$link_mode_expected"`

if [ "$mode_supported" != "$link_mode_expected" ] ||
    ( [ "$mode_supported" != "$mode_advertised" ] ) ; then
        
     #some action
fi

The above code is giving the correct result that is 15000baseKR/Full for both mode_advertised and mode_supported and I am doing the logic as above but I am looking for help with below

  1. how to avoid two ethtool commands, can we add the output to a buffer and grep from that buffer?
  2. what is the awk equivalent of the same and if awk is faster in execution?
  3. Is there any better approach than the above?

Advertisement

Answer

Awk will indeed be the answer to all your questions here.

link_mode_expected=15000

if ethtool "$eth_device" |
   awk -v lme="$link_mode_expected" '
      s && /:/ { s=0 }
      /Supported link modes:/ { s=1 }
      s && ($NF + 0 == lme) { sgood++ }
      a && /:/ { a=0 }
      /Advertised link modes:/ { a=1 }
      a && ($NF + 0 == lme) { agood++ }
      END { exit 1-(agood && sgood) }'
then
    # some action
fi

Demo, with some debug prints: https://ideone.com/v5du8g

Having Awk perform the comparison and set its exit status for if to examine is slightly clunky on the Awk side, but makes the script very easy and natural to use from the surrounding shell script.

Like sed, Awk processes one line (or, more specifically, one record) per iteration. In this script, the simple variables s and a reflect whether the current input line is inside a region which enumerates the supported or advertised modes, respectively. If we are in such a region, we check if the last field on the line ($NF) evaluates numerically (+ 0) to the number in lme. Awk conveniently ignores any nonnumeric tail on the value in this scenario. At the end, we set the exit status to 0 for success (both the values were found) or 1 otherwise, in accordance with the shell’s conventions (zero exit code means success, anything else is a failure).

As an alternative approach, you could try to figure out a record separator (RS) to split on, instead of newline. Splitting on a colon might be good, as then you can examine the entire region in one go (but then you lose the simple and elegant feature that NF contains the index of the field you want to examine, so it might not be simpler at all in the end).

You could also opt to simply have Awk extract and print the values, and then do the comparison in the shell; but having the shell parse the output from Awk which you just spent so much time parsing is stilted and unattractive.

This script isn’t entirely trivial, but you should find that learning enough Awk to write simpler scripts is quite pleasant and quick, and very well worth your time. You can get pretty far already on a budget of 30 minutes to an hour.

Ad-hoc output formats which require custom parsers are a constant source of frustration and friction. Increasingly, modern tools have options to produce output in properly machine-readable standard formats like JSON, YAML, or XML. Alas, ethtool unfortunately does not seem to have any such facility.

5 People found this is helpful
Advertisement