【问题标题】:producing df command a grand total specific filesystem生成 df 命令一个总计的特定文件系统
【发布时间】:2018-01-12 14:46:06
【问题描述】:

只需要做一些我可以自己处理的基本事情,但结果我对我得到的结果表示怀疑......

我需要在两个不同服务器上的特定文件系统上使用 df 命令生成总计。

ssh server1 df -mP | egrep "/dev/md10|/dev/md11" | sort ; ssh server1 df -mP --total | grep "total" | egrep -v "/dev/md10|/dev/md11

结果:

/dev/md10                                                   183004016  87303581  95700436      48% /si001c1
/dev/md11                                                   183004016 165986430  17017587      91% /si001c2
total                                                       366565396 253332843 113232554      70%

然后我在第二台服务器上使用相同的命令来获取总数。我的问题,我得到的总计似乎不正确(我不确定)以及如何通过使用单行命令或作为 bash 中的基本脚本结合使用相同的命令来生成总计。感谢您的帮助。

更新: 这是遵循@EdmCoff 指南后的更新。

printf "Grand total: " ; (ssh server1 df -m /dev/md11 ; ssh server2 df -m /dev/md1*) | awk 'a+=$2;b+=$3;c+=$4;d+=$5/3} END {print a" "b" "c" "d%}'

结果:

Grand total: 549012050 501832399 47179652 92%

构建一个脚本(重新完成):

#!/bin/bash
(ssh server1 df -m --no-sync "/dev/md11" ; ssh server2 df -m --no-sync "/dev/md1*") | sed -e /^Filesystem/d | sort > df_udsall
#(cat df_udsall)
printf "\nUDS:\nserver1 & server2\n"
printf "Mounted on       Free space   Disk usage   Use"%%"   Disk state"
while read df_udsall 
do
USAGE=$(echo $df_udsall ; echo $grand_total) | awk '{print $5}' | cut -d"%" -f1
if [[ "$USAGE" -ge " 95" ]]
then
STATUS='CRITICAL'
elif [[ "$USAGE" -ge " 90" ]]
then
STATUS='WARNING'
else
STATUS='OK'
fi
printf "$(echo $df_udsall | awk '{print $6, $4, $3, $5}' > df_udsall_stats)"
column -t df_udsall_stats | perl -ne 'chomp ; printf "\n%-18s %8s %12s %6s %-2s", split / +/' ; printf "`echo -ne $STATUS`"
done < df_udsall
printf "\n\nGrand total " ; cat df_udsall | awk '{b+=$4;c+=$3;d+=$5/3} END {print b" "c" "d "%"}' > grand_total
column -t grand_total | perl -ne 'chomp ; printf "%15s %12s %6s %-2s", split / +/' ; printf "`echo -ne $STATUS`"
rm -f df_udsall df_udsall_stats grand_total

上面的脚本需要一些微调。

预期结果:

UDS:
server1 & server2
Mounted on         Free space   Disk usage   Use%   Disk state
/sic1                16202762    166801255    92%   WARNING
/sic2                15648157    167355860    92%   WARNING
/sic3                15256569    167747448    92%   WARNING

Grand total:         47107488    501904563    92%   OK

固定三元组脚本输出结果:

UDS:
server1 & server2
Mounted on         Free space   Disk usage   Use%   Disk state
/sic001c1          92146461     90857556    50% OK
/sic001c2          16873531    166130486    91% WARNING
/sic001c3          16832710    166171307    91% WARNING
/sic001c4          16362388    166641629    92% WARNING

Grand total:       142215090    589800978     81 OK%

【问题讨论】:

  • 总是root 用户保留文件系统的百分之几。所以你的总数没有加起来并不奇怪
  • 为了将您的两个命令合并为一个总计,您是否考虑过只使用 awk?我正在想象类似(command for server 1; command for server 2) | awk '/total/ {a+=$2;b+=$3;c+=$4} END {print a" "b" "c}'
  • @EdmCoff 感谢您的命令,但我仍然更喜欢在上面提到的两台服务器上或多或少获得相同结果的东西。我不是 Linux 人,但每天玩起来很有趣,因为我很想尝试与其他操作系统不同的东西。我尝试运行命令(ssh server1 df -mP --total /dev/md1* ; ssh server2b df -mP --total /dev/md1*) | awk '/total/ {a+=$2;b+=$3;c+=$4} END {print a" "b" "c}',但结果不如预期。学习一些我实际上不知道的新命令是件好事。
  • 对不起,我误解了你所说的总计的意思(我以为你想合并两个服务器的总计)。假设您想同时对三列求和,我的建议仍然是 awk。所以,ssh server1 df -mP /dev/md1* | awk '{a+=$2;b+=$3;c+=$4} END {print a" "b" "c}'(即你的命令没有总和所有列)或ssh server1 df -mP --total /dev/md1* | awk '!/total/ {a+=$2;b+=$3;c+=$4} END {print a" "b" "c}'(即在你的命令中包括总数,但在 awk 命令中排除它)。
  • 如果你真的想使用 bc,我建议像ssh server1 df -mP /dev/md1* | tr -s ' ' | cut -d" " -f 2,2 | paste -sd+ - | bc 这样我使用tr 命令将多个空格替换为一个空格,cut 命令只是第二列数字,paste 命令将列重新格式化为 num1+num2+num3+etcetera,bc 命令进行数学运算。显然,您需要更改要求和的列的剪切命令。

标签: bash linux-disk-free


【解决方案1】:

这里尝试将脚本重构为 Awk 完全控制输出的计算和格式的版本,正如几个 cmets 中所建议的那样。我有内联的 cmets,你可能想删除它们。

#!/bin/bash
# use a loop to reduce duplication of ssh options etc
while read -r server mounts; do
    ssh "$server" df -m --no-sync $mounts </dev/null
done <<\____SERVER__MOUNTS |
    server1 /dev/md10 /dev/md11
    server2 /dev/md12 /dev/md13
____SERVER__MOUNTS
# sed -e /^Filesystem/d inlined into Awk below
sort |
# pipe into awk
awk 'BEGIN { print "UDS:\nserver1 & server2"
        # Maybe use printf here too
        print "Mounted on         Free space   Disk usage   Use%   Disk state"
        fmt="%-18s %8i %12i %6s %-2s"
    }
    function status(num) {
        # Awk conveniently ignores any trailing string
        # so you can compare 95% to 95 numerically
        if (num > 95) result="CRITICAL"
        else if (num > 90) result="WARNING"
        else result="OK"
        return(result)
    }
    ! /^Filesystem/ {
        printf fmt "\n", $6, $4, $3, $5, status($5)

        # EdmCoff''s hack, too lazy to change to legible variable names
        # adapted to defer division until we know the final value of n
        a+=$2;b+=$3;c+=$4;dd+=$5;n++
    }
    END { d=dd/n;
        printf "\n" fmt "%%\n",
     "Grand total:", c, b, int(d), status(d) }'

我显然无法用真实输入来测试它,所以可能存在轻微的格式错误等。我希望我捕获了足够的逻辑,至少可以向您展示如何将这个处理的主体实现为 Awk 脚本。

请注意没有任何临时文件(如果被中断,您的原始脚本将无法清理这些文件;use trap)以及使用缩进来帮助您查看循环和条件。

【讨论】:

  • 感谢脚本,但我不理解它的某些功能,这给了我一个错误。 awk:命令。 line:12: (FILENAME=- FNR=1) fatal: 没有足够的参数来满足格式字符串 `%-18s %8s %12s %6s %-2s %s ' ^ 用完这个
  • 我编辑了答案以删除您询问的尾随%s,但可能还有更多;我显然没有办法测试这个。如果你能提供一些真实的测试数据,那么根除任何剩余的错误应该不难。
  • Awk 代码是您的 shell 脚本的一个非常简单的一对一翻译,但如果您有什么特别不明白的地方,请询问,我会尽力澄清。它实际上只是从不是/^Filesystem/ 行的每一行中提取几个字段并从您的代码中执行计算。
  • 我运行了脚本,起初看起来不错。然后我注意到脚本没有看到 server2 设备,只显示 server1 设备。每台服务器有 2 台设备。所以我改变了#6 & #7 server1 /dev/md10 /dev/md11 & server2 /dev/md12 /dev/md13,server1 OK 但不是 server2。我需要将百分比四舍五入,不带小数和磁盘状态阈值。我真的不知道如何把它放在一起。
  • 计算d 的更好方法是100.0*c/(c+b),但我现在将其作为评论留下。
猜你喜欢
  • 1970-01-01
  • 2014-06-02
  • 2019-12-15
  • 2015-12-25
  • 2013-10-31
  • 2017-10-04
  • 1970-01-01
  • 2012-02-02
  • 1970-01-01
相关资源
最近更新 更多