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
- how to avoid two
ethtool
commands, can we add the output to a buffer and grep from that buffer? - what is the awk equivalent of the same and if awk is faster in execution?
- Is there any better approach than the above?
CodePudding user response:
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.