【问题标题】:Extract temperature from data bash从数据bash中提取温度
【发布时间】:2014-08-15 09:02:36
【问题描述】:

我使用的是Mac软件Temperature Monitor的命令行工具,看起来像这样:

$ /Applications/TemperatureMonitor.app/Contents/MacOS/tempmonitor -c -l -a


SMART Disk Hitachi HTS547550A9E384 (J2250050GMBY3C): 30 C
SMART Disk TOSHIBA MK5065GSXF (71SNCPW4T): 28 C
SMC BATTERY: 30 C
SMC BATTERY POSITION 2: 31 C
SMC BATTERY POSITION 3: 28 C
SMC CPU A DIODE: 47 C
SMC CPU A PROXIMITY: 45 C
SMC GPU 1 CHIP: 40 C
SMC LEFT PALM REST: 28 C
SMC MAIN HEAT SINK 2: 38 C
SMC MAIN HEAT SINK 3: 37 C
SMC MAIN LOGIC BOARD: 36 C
SMC PLATFORM CONTROLLER HUB: 49 C
SMC SSD BAY: 36 C

我想稍微清理一下。例如,假设我想获得三个电池温度读数的平均值。我想通过管道输入grep 获取电池,然后awk 遍历所有字段以获取正确数据,但这似乎真的很混乱。

所以我希望三个变量 $BATTERY_1、$BATTERY_2 和 $BATTERY_3 分别具有内容 30、31 和 28。

对最干净的方法有什么建议吗?

【问题讨论】:

    标签: bash parsing awk grep


    【解决方案1】:

    创建一个数组然后将数组中的值移动到普通变量中会更容易。使用awk进行提取很简单:

    TEMPMON="/Applications/TemperatureMonitor.app/Contents/MacOS/tempmonitor"
    battery=( $("$TEMPMON" -c -l -a | awk '/BATTERY/ { print $(NF-1) }') )
    BATTERY_1=${battery[0]}
    BATTERY_2=${battery[1]}
    BATTERY_3=${battery[2]}
    

    【讨论】:

    • 太棒了。快速的问题,假设我想对磁盘进行相同的过程(我目前正在这样做),我宁愿不必再次运行程序,当我尝试将输出保存到变量时,然后 awking那个变量,它没有给我正确的输出。有没有解决的办法?因为我目前正在运行程序7次,只是为了得到我刚刚扔掉的数据,我只是觉得……脏。
    • 最简单的方法是运行一次命令,将输出保存到文件中。然后,您可以使用awk 或任何其他工具多次处理该文件(7 次,或根据需要多次)。或者,您可以决定让awk 打印更多值,并使用数组索引将值保存到正确的变量中。或者您可以让awk 进行计算和格式化;它完全能够计算平均值并以您可能需要的大多数格式打印数据。
    • 是的,但是当我将结果保存到一个变量时,它会删除新行,当我 awk 数据时,它只需要最后一个实例。
    • 谢谢你,你帮了大忙!
    【解决方案2】:

    补充@Jonathan Leffler's helpful answer

    如果您实际上并不需要单个值,而是只需要平均值,请尝试:

    ... | awk '/ BATTERY/ {sum+=$(NF-1); ++i} END {OFMT="%.2f"; print sum / i}'
    
    • OFMT="%.2f" 将(printf 样式)输出数字格式设置为 2 位小数,结果为 29.67

    更新:OP 在评论中要求<Item name>: <avg temp> (<temp 1>, <temp 2>, <temp 3>) 格式输出:

    ... | awk -v itm='BATTERY' '
      $0 ~ itm {
        vals = vals (i ? " " : "") $(NF-1)
        sum += $(NF-1); ++i
      } 
      END {
        printf "%s: %.2f (%s)\n", itm, sum / i, vals
      }'
    
    • -v itm='BATTERY' 将要匹配的项目名称作为 awk 变量 itm 传递。
    • $0 ~ itm 匹配 (~) 当前输入行 ($0) 与 itm(解释为正则表达式,在这种简单的情况下执行子字符串匹配)。
    • awk 默认情况下将输入行拆分为字段$1$2、...,并将字段数存储在特殊变量NF 中。由于输入数据中的值位于倒数第二个字段中,$(NF-1) 引用每一行的值。
    • vals = ... 建立一个匹配值的字符串列表;请注意仅将字符串和变量彼此相邻放置如何导致它们被连接(作为字符串)。
      • (i ? " " : "") 是 C 风格的三元条件,如果条件 i 为真(即,如果变量 i 具有 非零 值)则返回单个空格,否则返回空字符串。换句话说:如果该值不是 first 之一,则在将值附加到迄今为止建立的值列表之前附加一个空格。请注意,awk 中的未初始化变量在字符串上下文中默认为空字符串,在数字/布尔上下文中默认为 0(假)。
    • sum += ... 将值相加; ++i 保留值的计数。
    • END 是一种特殊模式,其关联的动作(块)在所有输入行之后处理。
    • printf,用于基于格式(模板)字符串的输出,其工作方式与 C 对应项类似,在这种情况下输出项目名称(第一个 %s,用 itm 实例化),具有 2 个小数位的平均值(@ 987654350@,用sum / i 实例化)和值列表(最后一个%s,用vals 实例化)。

    【讨论】:

    • 太棒了。我似乎对awk一无所知。你有什么好的资源可以推荐吗?我一直需要它。我最近进入了 Geektool,我无法停止......
    • 我也对个人价值观感兴趣。我的格式是 : (, , ),以防一个项目更高,而我错过了一个潜在的问题。有点违背了目的。
    • @JShoe:恐怕我没有个人推荐,除了阅读man 页面并在SO 上研究答案 - 这里有很多awk 专家。另请注意,有不同的实现对 POSIX 标准进行了不同的扩展; GNU awk 是最强大的。这是 POSIX awk 手册页:man.cx/awk
    • @JShoe Re <Item name>: <avg temp> (<temp 1>, <temp 2>, <temp 3>):查看我的更新 - 希望解释对您有所帮助。
    • @JShoe。不客气;我已经做了更详细的解释,也许这会有所帮助。如果您真的想学习如何使用 awk,这可能是一个很好的起点,因为它包含几个标准的 awk 习语——而且您知道它的作用应该有助于学习它。
    猜你喜欢
    • 2019-06-21
    • 2018-12-27
    • 2013-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多