You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用sed/awk解析ethtool输出的Shell脚本优化问询

问题描述

我正在编写Shell脚本,需要从ethtool命令输出中解析网卡的支持链路模式(Supported link modes)与通告链路模式(Advertised link modes),并与预期值匹配——要求预期值需同时存在于两种模式中才满足条件。

现有ethtool输出示例:

# 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

我当前使用的脚本代码如下:

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

当前代码可正常获取结果(两种模式均返回15000baseKR/Full),但有以下优化需求:

  1. 如何避免重复执行两次ethtool命令,能否将输出存入缓存后再进行匹配?
  2. 实现相同功能的awk等价写法是什么?awk的执行效率是否更高?
  3. 是否存在比当前方案更优的实现思路?

解决方案

1. 缓存ethtool输出,避免重复执行

把ethtool的输出一次性存入变量,之后从变量里提取内容即可,无需重复调用命令:

link_mode_expected=15000baseKR
eth_device=eth5

# 一次性获取ethtool输出并缓存
ethtool_output=$(ethtool "$eth_device")

# 从缓存中提取支持的模式
mode_supported=$(echo "$ethtool_output" | sed -ne '/Supported link modes:/,/:/p' | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' | grep "$link_mode_expected")
# 从缓存中提取通告的模式
mode_advertised=$(echo "$ethtool_output" | sed -ne '/Advertised link modes:/,/:/p' | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' | grep "$link_mode_expected")

if [ -z "$mode_supported" ] || [ -z "$mode_advertised" ]; then
    # 预期模式不同时存在于两种模式中,执行动作
    echo "Expected link mode $link_mode_expected not found in both supported and advertised modes"
    # some action
fi

这里还优化了判断逻辑:直接检查两个变量是否为空,只要有一个为空,就说明预期模式不存在,符合需求。

2. awk等价写法及效率对比

用awk可以一次性完成解析和判断,无需多次管道调用,代码更简洁,执行效率也更高(减少了进程创建的开销):

link_mode_expected=15000baseKR
eth_device=eth5

ethtool "$eth_device" | awk -v expected="$link_mode_expected" '
    /Supported link modes:/ { in_supported=1; next }
    in_supported && /:/ { in_supported=0 }
    in_supported { if ($0 ~ expected) supported=1 }

    /Advertised link modes:/ { in_advertised=1; next }
    in_advertised && /:/ { in_advertised=0 }
    in_advertised { if ($0 ~ expected) advertised=1 }

    END {
        if (!(supported && advertised)) {
            print "Expected link mode " expected " not found in both modes"
            exit 1 # 返回非0状态码,方便后续脚本判断
        }
    }
'

# 根据awk的返回值执行后续动作
if [ $? -ne 0 ]; then
    # some action
fi

效率对比:

awk是单进程处理,而原脚本(包括缓存后的版本)会创建多个sed、grep进程,所以awk的执行效率明显更高,尤其是在需要批量处理多个网卡时,差异会更明显。

3. 更优的实现思路

可以进一步简化逻辑,直接在awk中完成所有判断,甚至不需要额外变量存储输出,同时可以更精确地匹配模式(避免部分匹配的问题,比如预期1000baseKX时不会匹配到10000baseKR):

link_mode_expected=15000baseKR
eth_device=eth5

# 精确匹配完整模式行(包含/Full后缀)
ethtool "$eth_device" | awk -v expected="$link_mode_expected/Full" '
    BEGIN { supported=0; advertised=0 }
    /Supported link modes:/ { section="supported"; next }
    /Advertised link modes:/ { section="advertised"; next }
    /:/ { section="" } # 离开模式区域
    section != "" {
        gsub(/^[[:space:]]+|[[:space:]]+$/, "", $0) # 去除前后空格
        if ($0 == expected) {
            if (section == "supported") supported=1
            else if (section == "advertised") advertised=1
        }
    }
    END {
        exit !(supported && advertised)
    }
'

if [ $? -ne 0 ]; then
    echo "Expected link mode $link_mode_expected is not fully supported and advertised"
    # some action
fi

另外,也可以用grep一次性匹配两个模式区域,但可读性不如awk,且需要预估模式行数量(-A5表示取匹配行后5行),如果模式数量超过这个值会漏判:

link_mode_expected=15000baseKR
eth_device=eth5

ethtool_output=$(ethtool "$eth_device")
# 检查是否同时存在于两个区域
if ! grep -q -A5 "Supported link modes:" <<< "$ethtool_output" | grep -q "$link_mode_expected" || \
   ! grep -q -A5 "Advertised link modes:" <<< "$ethtool_output" | grep -q "$link_mode_expected"; then
    # some action
fi

内容的提问来源于stack exchange,提问作者pradiptart

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 04:35:28