您好,我需要一个脚本来使用 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。我怎样才能做到这一点?
最佳答案
首先,bash 中没有“元组”这样的东西。阵列是完全平坦的。这意味着您要么拥有“标量”变量,要么拥有一级标量数组。
您面临的任务有多种方法。要么:
- 如果您使用的是足够新的 bash (4.2 AFAIR),则可以使用关联数组(散列、映射或您如何调用它)。然后,CPU 名称将是键,数字将是值;
- 创建一个普通数组(类似 perl 的哈希),其中奇数索引将包含键(CPU 名称),偶数索引将包含值。
- 创建两个单独的数组,一个包含 CPU 名称,另一个包含值,
- 只创建一个数组,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})
请注意我为简化脚本所做的一些更改:
- awk 现在输出“cpu-name number”,每行一个,由一个空格分隔;
- 核心计数不是由 awk 输出(以避免预处理输出),而是从输出中的行数推导出来,
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} )
注意:
- awk 输出格式已更改以适应关联数组语义,
totals
声明为关联数组(declare -A
),- 遗憾的是,必须使用
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 名称和值发生在循环中)。
关于linux - 使用 awk 从文件中读取元组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11608323/