1

嗨,我需要一个脚本来使用 awk 从 /proc/interrupts 文件中读取 eth 中断数,并找到每个 CPU 内核的中断总数。然后我想在 bash 中使用它们。文件的内容是;

      CPU0       CPU1       CPU2       CPU3

47:   33568      45958      46028      49191     PCI-MSI-edge    eth0-rx-0
48:     0          0          0          0       PCI-MSI-edge      eth0-tx-0
49:     1          0          1          0       PCI-MSI-edge      eth0
50:   28217      42237      65203      39086     PCI-MSI-edge    eth1-rx-0
51:     0          0          0          0       PCI-MSI-edge      eth1-tx-0
52:     0          1          0          1       PCI-MSI-edge      eth1
59:     114991     338765      77952     134850  PCI-MSI-edge eth4-rx-0
60:     429029     315813     710091      26714  PCI-MSI-edge eth4-tx-0
61:      5          2          1          5      PCI-MSI-edge     eth4
62:    1647083     208840    1164288     933967  PCI-MSI-edge eth5-rx-0
63:     673787    1542662     195326    1329903  PCI-MSI-edge eth5-tx-0
64:     5          6          7          4       PCI-MSI-edge      eth5

我在这段代码中用 awk 读取这个文件:

#!/bin/bash

 FILE="/proc/interrupts"

 output=$(awk 'NR==1 {
 core_count = NF 
 print core_count
 next
}
/eth/ {
 for (i = 2; i <= 2+core_count; i++)
 totals[i-2] += $i
}

END {
 for (i = 0; i < core_count; i++)
 printf("%d\n", totals[i])
}
' $FILE)

core_count=$(echo $output | cut -d' ' -f1)

output=$(echo $output | sed 's/^[0-9]*//')

totals=(${output// / })

在这种方法中,我处理总核心数,然后处理每个核心的总中断,以便在我的脚本中对它们进行排序。但我只能处理总数数组中的数字,例如这个,

    totals[0]=22222
    totals[1]=33333

但是我需要将它们作为具有 CPU 内核名称的元组来处理。

    totals[0]=(cPU1,2222)
    totals[1]=(CPU',3333)

我想我必须将名称分配给一个数组,并将它们作为我的 SED 中的元组读入 bash。我怎样才能做到这一点?

4

1 回答 1

0

首先,bash 中没有“元组”这样的东西。阵列是完全平坦的。这意味着您要么有一个“标量”变量,要么有一个级别的标量数组。

您面临的任务有多种方法。任何一个:

  1. 如果您使用的是足够新的 bash(4.2 AFAIR),则可以使用关联数组(散列、映射或您如何称呼它)。然后,CPU 名称将是键,数字将是值;
  2. 创建一个普通数组(类似 perl 的哈希),其中奇数索引将包含键(CPU 名称),偶数索引将包含值。
  3. 创建两个单独的数组,一个带有 CPU 名称,另一个带有值,
  4. 只创建一个数组,CPU 名称与值之间用某个符号(即=:)分隔。

让我们先介绍方法 2:

#!/bin/bash

FILE="/proc/interrupts"

output=$(awk 'NR==1 {
    core_count = NF
    for (i = 1; i <= core_count; i++)
        names[i-1] = $i
    next
}
/eth/ {
    for (i = 2; i <= 2+core_count; i++)
        totals[i-2] += $i
}

END {
    for (i = 0; i < core_count; i++)
        printf("%s %d\n", names[i], totals[i])
}
' ${FILE})

core_count=$(echo "${output}" | wc -l)
totals=(${output})

请注意我为使脚本更简单而进行的一些更改:

  1. awk 现在输出“cpu-name number”,每行一个,用一个空格分隔;
  2. 核心数不是由 awk 输出的(以避免预处理输出),而是从输出中的行数推导出来的,
  3. totals数组是通过展平输出创建的——空格和换行符都将被视为空格并用于分隔值。

结果数组如下所示:

totals=( CPU0 12345 CPU1 23456 ) # ...

要对其进行迭代,您可以使用类似(简单的方法):

set -- "${totals[@}}"
while [[ $# -gt 0 ]]; do
    cpuname=${1}
    value=${2}

    # ...

    shift;shift
done

现在让我们为方法 1 修改它:

#!/bin/bash

FILE="/proc/interrupts"

output=$(awk 'NR==1 {
    core_count = NF
    for (i = 1; i <= core_count; i++)
        names[i-1] = $i
    next
}
/eth/ {
    for (i = 2; i <= 2+core_count; i++)
        totals[i-2] += $i
}

END {
    for (i = 0; i < core_count; i++)
        printf("[%s]=%d\n", names[i], totals[i])
}
' ${FILE})

core_count=$(echo "${output}" | wc -l)
declare -A totals
eval totals=( ${output} )

注意:

  1. 已更改 awk 输出格式以适应关联数组语义,
  2. totals被声明为关联数组 ( declare -A),
  3. 可悲的是,eval必须用来让 bash 直接处理输出。

结果数组如下所示:

declare -A totals=( [CPU0]=12345 [CPU1]=23456 )

现在您可以使用:

echo ${totals[CPU0]}

for cpu in "${!totals[@]}"; do
    echo "For CPU ${cpu}: ${totals[${cpu}]}"
done

第三种方法可以通过多种不同的方式完成。假设您可以允许两次读取/proc/interrupts,您甚至可以这样做:

FILE="/proc/interrupts"

output=$(awk 'NR==1 {
    core_count = NF
    next
}
/eth/ {
    for (i = 2; i <= 2+core_count; i++)
        totals[i-2] += $i
}

END {
    for (i = 0; i < core_count; i++)
        printf("%d\n", totals[i])
}
' ${FILE})

core_count=$(echo "${output}" | wc -l)
names=( $(cat /proc/interrupts | head -n 1) )
totals=( ${output} )

所以,现在 awk 再次只输出计数,而名称是通过 bash/proc/interrupts直接从第一行获取的。或者,您可以从方法 (2) 中获得的单个数组创建拆分数组,或者以其他方式解析 awk 输出。

结果将在两个数组中:

names=( CPU0 CPU1 )
totals=( 12345 23456 )

并输出:

for (( i = 0; i < core_count; i++ )); do
    echo "${names[$i]} -> ${totals[$i]}"
done

最后一种方法:

#!/bin/bash

FILE="/proc/interrupts"

output=$(awk 'NR==1 {
    core_count = NF
    for (i = 1; i <= core_count; i++)
        names[i-1] = $i
    next
}
/eth/ {
    for (i = 2; i <= 2+core_count; i++)
        totals[i-2] += $i
}

END {
    for (i = 0; i < core_count; i++)
        printf("%s=%d\n", names[i], totals[i])
}
' ${FILE})

core_count=$(echo "${output}" | wc -l)
totals=( ${output} )

现在(常规)数组看起来像:

totals=( CPU0=12345 CPU1=23456 )

你可以像这样解析它:

for x in "${totals[@]}"; do
    name=${x%=*}
    value=${x#*=}
    echo "${name} -> ${value}"
done

(现在请注意,拆分 CPU 名称和值发生在循环中)。

于 2012-07-23T08:21:40.943 回答