使用 df 并尝试 awk 特定列

使用 df 并尝试 awk 特定列

在我试图制作的这个脚本的其他问题中(这是我制作的第一个 unix/linux 脚本),我试图使用 df 来获取已使用的磁盘空间的百分比并将其通过电子邮件发送到根目录。我们的指示是从 df 中排除 /proc 软盘和 cdrom。

到目前为止我所拥有的:

fsExclude=(/proc /dev/floppy /dev/cdrom) #Exclusions from df file system
fsUsed=15 #percent to watch for
WarnEmail=root #email for warning message
if (df -x $fsExclude | awk '$5' | sed '2p' > fsUsed)
then
df -h > dfFile.tmp
mail -s "WARNING: Almost out of disk space %" '$WarnEmail' < dfFile.tmp
rm dfFile.tmp
fi

现在我知道这有一些问题。当我运行它只是为了看看得到什么样的输出时,我得到了(第一行是上面我没有包含的 if 语句上方的一条消息):

Emailing admin, disk almost full...
3 
$WarnEmail... User unknown 
60 
awk:    cmd. line:1: print $4 
awk: cmd. line:1: ^ parse error    
/root/dead.letter... Saved message in /root/dead.letter 

还有更多,但我会留到以后再讲。我已经以类似的方式将根邮寄到了脚本之外,没有出现任何问题,但在脚本中它不想工作。使用 df 输出的 awk,我只想从 %used 列中获取值,看看它是否大于或小于 fsUsed 值。如果是,请进去并将整个 df 输出通过电子邮件发送给 root。我在谷歌搜索时看到有人建议使用带有 -perc 或 -avail 的东西,但在这里都不起作用。它会告诉我这些都是未知的,所以我尝试回到 awk。

任何有关解决此问题的帮助将不胜感激。

答案1

您遇到的主要问题是

  1. fsExclude是一个数组,要获取其所有元素,您需要${array[@]}.无论如何,该-x选项需要文件系统类型,而不是设备。

  2. 您的命令中存在语法错误awk,您想要

    awk '{print $5}' 
    

    如果没有print,将采用计算结果为第 5 个字段是否存在的awk表达式,因此将打印至少包含 5 个字段的所有行。$5true

  3. 如果我理解你的目标,你似乎想将当前百分比与 的值进行比较fsUsed。但是,您的命令创建一个名为 的文件fsUsed并打印该文件的输出df。你想要的是

    if [ "$(df -x $fsExclude | awk '$5' | sed '2p')" -gt "$fsUsed" ]
    

    称为$()命令替换并扩展到您运行的任何命令的输出。这就是你想要比较的价值并且fsUsed要获取该值,您需要$

  4. 您有$WarnEMail单引号,这意味着它被视为字符串文字而不是变量。试试这个:

    mail -s "WARNING: Almost out of disk space %" "$WarnEmail" < dfFile.tmp
    
  5. 您的df命令将返回多行,但您正在运行单个比较,这是行不通的。您需要检查df输出的每一行:

然后,你也在以一种不必要的复杂方式来做这件事。为什么不是这样的:

#!/bin/bash
fsExclude="/proc|/dev/floppy|/dev/cdrom" #Exclusions from df file system
fsUsed=15 #percent to watch for
WarnEmail=root #email for warning message
problem=0;
df | grep -v "$fsExclude" |
    while read line
    do
    ## Check the percentage, send the mail if at least
    ## one mount point's percentage is > $fsUsed
    if [[ $(grep -oE '[0-9]+%' <<<"$line" | tr -d '%') -gt $fsUsed ]]
    then
        ## I'm not sure if `command | mail` works and I don't have a system
        ## I can test it on. If it doesn't, use a file as you did before. 
        df -h | mail -s "WARNING: Almost out of disk space %" "$WarnEmail" 
        ## No need to rpocess any more lines, exit the while loop
        break;
    fi
    done

答案2

精彩节目:

  • 您正在运行命令df -x /proc /dev/floppy /dev/cdrom。这告诉df我们跳过/proc不存在的类型的文件系统(文件系统类型将为proc),并仅列出/dev/floppy/dev/cdrom。无法忽略特定设备,您可以将其过滤掉。

  • 要打印 awk 中的第五个字段,请使用:这会在每一行上awk '{print $5}'执行指令。如果第五个字段不为零或空(是一个条件;由于没有相应的操作,因此执行默认操作,并打印整行),则打印整行。是一个语法错误。print $5awk '$5'$5awk 'print $5'

  • 在 中sed '2p' > fsUsed,该>符号是重定向运算符:sed 命令的输出被写入临时文件fsUsed

  • '$WarnEmail'是一个文字字符串,由以美元符号开头的 10 个字符组成。要展开变量引用,请使用双引号。

还:

  • 不要使用临时文件来存储一些小输出。使用命令替换将其放入变量中。

  • 当您解析其输出时将该-P选项传递给。df否则,当设备路径太长时,可能会在记录中间添加换行符。

  • 您可以在 awk 中完成所有过滤。

这是编写将电子邮件合并为一封的脚本的另一种方法。

body=$(df -P | awk -v fsUsed=15 fsExclude='/dev/floppy /dev/cdrom' '
    BEGIN {split(fsExclude, fsExcludeArray)}
    NR == 1 {next}           # skip the header line
    $1 in fsExcludeArray {next}
    {$5 = sub(/%/, "")}      # remove the % character from the Use% column
    $5 > fsUsed {print}      # print lines with almost-full disks
')
if [ -n "$body" ]; then
  # $body is non-empty: there is at least one almost-full filesystem
  echo "$body" | mail -s "Warning: some filesystems are almost full" "$WarnEmail"
fi

相关内容