如何在bash中遍历命令输出的每一行?

时间:2013-12-09 04:35:33

标签: bash

我有一个从/proc/stat读取的脚本并计算CPU使用率。 /proc/stat中有三个相关的行:

cpu  1312092 24 395204 12582958 77712 456 3890 0 0 0
cpu0 617029 12 204802 8341965 62291 443 2718 0 0 0
cpu1 695063 12 190402 4240992 15420 12 1172 0 0 0

目前,我的脚本只读取第一行并计算其使用情况:

cpu=($( cat /proc/stat | grep '^cpu[^0-9] ' ))
unset cpu[0]
idle=${cpu[4]}
total=0
for value in "${cpu[@]}"; do
  let total=$(( total+value ))
done

let usage=$(( (1000*(total-idle)/total+5)/10 ))
echo "$usage%"

这可以按预期工作,因为脚本只解析这一行:

cpu  1312092 24 395204 12582958 77712 456 3890 0 0 0

很容易只获得以cpu0cpu1

开头的行
cpu=$( cat /proc/stat | grep '^cpu[0-9] ' )

但我不知道如何迭代每一行并应用同样的过程。我已经尝试在子shell中重置内部字段分隔符,如下所示:

cpus=$( cat /proc/stat | grep '^cpu[0-9] ' )
(
IFS=$'\n'
for cpu in $cpus; do
    cpu=($cpu)
    unset cpu[0]
    idle=${cpu[4]}
    total=0
    for value in "${cpu[@]}"; do
        let total=$(( total+value ))
    done
    let usage=$(( (1000*(total-idle)/total+5)/10 ))
    echo -n "$usage%"
done
)

但这会给我一个语法错误

line 18: (1000*(total-idle)/total+5)/10 : division by 0 (error token is "+5)/10 ")

如果我在循环中回显cpu变量,看起来它正确地分隔了这些行。我查看this thread,我认为我正确地将cpu变量分配给一个数组但是还有另一个错误我没看到?

我将我的脚本放入whats wrong with my script并且除了在cat内使用$()的警告之外,它没有向我显示任何错误,我很难过。

2 个答案:

答案 0 :(得分:2)

在循环中间更改此行:

IFS=' ' cpu=($cpu)

你需要这个,因为在你的循环外你设置IFS=$'\n', but with that setting cpu($ cpu)`将不会达到预期的效果。

顺便说一句,我会像这样写你的剧本:

#!/bin/bash -e

grep ^cpu /proc/stat | while IFS=$'\n' read cpu; do
    cpu=($cpu)
    name=${cpu[0]}
    unset cpu[0]
    idle=${cpu[4]}
    total=0
    for value in "${cpu[@]}"; do
        ((total+=value))
    done
    ((usage=(1000 * (total - idle) / total + 5) / 10))
    echo "$name $usage%"
done

使用awk的等价物:

awk '/^cpu/ { total=0; idle=$5; for (i=2; i<=NF; ++i) { total += $i }; print $1, int((1000 * (total - idle) / total + 5) / 10) }' < /proc/stat

答案 1 :(得分:2)

因为OP问了一个awk程序。

awk '
    /cpu[0-9] .*/ {
        total = 0
        idle = $5
        for(i = 0; i <= NF; i++) { total += $i; }
        printf("%s: %f%%\n", $1, 100*(total-idle)/total);
    }
' /proc/stat

/cpu[0-9] .*/表示“对与此表达式匹配的每一行执行”。 像$1这样的变量可以达到预期效果,但第一个字段的索引为1,而不是0:$0表示awk中的整行。