这是一个非常脆弱的脚本,基于看起来像旧版本的top。不过,检查这段脚本非常容易 - 所以,让我们来看看它。我们从以下内容开始:
top -b -n1
哪个(阅读top的手册)将top置于批处理模式(这意味着我们不想与top交互播放,而是希望将输出发送到另一个命令)并输出 1 次迭代。这将使我们得到如下输出:
$ top -b -n1
top - 10:48:33 up 1 day, 22:51, 3 users, load average: 1.21, 1.27, 1.03
Tasks: 262 total, 2 running, 260 sleeping, 0 stopped, 0 zombie
%Cpu(s): 14.5 us, 5.2 sy, 11.3 ni, 67.3 id, 1.6 wa, 0.0 hi, 0.1 si, 0.0 st
KiB Mem: 8124692 total, 6722112 used, 1402580 free, 384188 buffers
KiB Swap: 4143100 total, 430656 used, 3712444 free. 2909664 cached Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
11012 user1 20 0 426412 14436 5740 R 97.1 0.2 19:27.98 dleyna-renderer
4579 root 20 0 286480 152924 31152 S 13.0 1.9 24:15.49 Xorg
1 root 20 0 185288 4892 3352 S 0.0 0.1 0:02.52 systemd
2 root 20 0 0 0 0 S 0.0 0.0 0:00.02 kthreadd
3 root 20 0 0 0 0 S 0.0 0.0 0:02.77 ksoftirqd/0
5 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 kworker/0:0H
7 root 20 0 0 0 0 S 0.0 0.0 1:32.00 rcu_sched
当我们将其通过管道传递给grep ^Cpu ... 时,我们似乎发现了一些破损,表明我们在此答案中使用的top版本可能与原始脚本预期的版本不同。看起来意图是在^%Cpu上进行匹配。这是更正后的部分:
$ top -b -n1 | grep ^%Cpu
%Cpu(s): 14.6 us, 5.2 sy, 11.2 ni, 67.3 id, 1.6 wa, 0.0 hi, 0.1 si, 0.0 st
管道的下一部分是摆脱'%Cpu(s): '部分:
$ top -b -n1 | grep ^%Cpu | awk -F': ' '{print $2}'
15.1 us, 5.0 sy, 10.8 ni, 67.4 id, 1.6 wa, 0.0 hi, 0.1 si, 0.0 st
然后下一段...... awk -F% '{print $1}' - 对于这个答案的top版本再次没有意义,因为脚本正在寻找打印%符号左侧的内容 -我们的输出中没有%。所以......我们不知道我们需要从这里去哪里。
从脚本的其余部分...管道的结果与 100 进行比较...因此,我假设脚本要解析的top版本在第一列中占 CPU 利用率总数的百分比...在我们的顶级输出版本中,所有输出的粒度都更加精细。以下是前一个输出的细分:
15.1% -- spent in normal priority user/applications
5.0% -- spent in system/kernel
10.8% -- spent in low priority batch or daemon jobs
67.4% -- spent "idle"
1.6% -- spent waiting for I/O to complete
0.0% -- spent in servicing HW interrupts
0.1% -- spent in servicing software interrupts
0.0% -- spent stolen by another VM running on the HW
------------------------------------------------------
100.0% -- Total
...因此,在现代 Linux 系统上,top提供了更多信息,也许我们需要以不同的方式看待问题。在这种情况下,我们可以将 (idle * 10) 视为度量——就像在 shell 中一样,我们只有整数数学和比较可供我们使用。所以,我们将稍微调整一下脚本......在我们处理它的同时,让我们摆脱管道中的grep,因为这也可以通过awk轻松完成:
$ top -b -n1 | awk -F, '/^%Cpu/ {print $4}'
67.8 id
现在让我们调整它,让它只给我们乘以 10 的空闲值:
$ top -b -n1 | awk -F, '/^%Cpu/ { sub(/id/,"",$4); print $4*10 }'
678
好的,原始脚本的下一部分使用bc来查看我们是否被 100% 使用。由于我们现在关注的是空闲而不是利用率,因此我们想要与原始脚本相反。此外,由于输出被缩放为整数,我们不需要bc的复杂性。让我们在比较中使用shell?
$ if [ $(top -b -n1 | awk -F, '/^%Cpu/ { sub(/id/,"",$4); print $4*10 }') -le 0 ]; then echo '...'; fi
就是这样。
这个答案完全是为了展示代码是如何工作的——如何通过管道解释和解析top的输出,如何执行弄清楚一段脚本的作用,以及如何修复脆弱/损坏的脚本。然而,原始脚本不仅脆弱,而且在设计上几乎被破坏了。我们用来检测过载系统的指标更像是在top命令输出的第一行中找到的“平均负载”,甚至可以从uptime命令的输出中解析出来。
找出过载的一种方法可能是查看负载平均值除以 CPU 的数量。可以通过解析 /proc/cpuinfo 轻松找到 cpu 的数量:
$ grep ^processor /proc/cpuinfo | wc -l
4
这是一个示例,其中 15 分钟内的 400% 负载被视为连续负载阈值:
load=$(uptime | awk -F, '{ print $(NF) * 1.0 }')
proc=$(grep ^processor /proc/cpuinfo | wc -l)
plod=$(awk "BEGIN { x = 100 * $load / $proc; print int(x) + int(x+x)%2 }")
if [ $plod -gt 400 ]; then echo '...'; fi
注意:int(x) + int(x+x)%2是一个舍入函数
对于系统上的可用内存量,我喜欢schtever的回答——除了我会使用第 4 列而不是第 3 列并检查内存是否不足。