FreeBSD下cron执行df脚本显示存储容量为实际值两倍的问题
我碰到过类似的FreeBSD cron环境下的工具行为差异问题,结合你的描述,这个问题大概率和df的单位处理或者cron的环境变量细节有关,不是脚本逻辑本身的问题。下面给你几个具体的排查方向和解决建议:
1. 先锁定df的单位,避免环境变量干扰
FreeBSD的df命令输出的数值会受环境变量BLOCKSIZE影响:手动执行时你的bash环境可能默认设置了BLOCKSIZE=1024(1KB),但cron的默认环境里这个变量可能是512字节(FreeBSD的原生块大小),这就导致数值看起来直接翻倍了(因为1KB=2*512字节)。
解决起来很简单,在脚本里给df显式指定单位就行:
# 改用df -k强制以KB为单位输出,和zfs list的默认单位对齐 df -k | awk '/datapool\// {print $1, $3, $4}'
这样不管cron或者手动环境的BLOCKSIZE是什么,输出的数值都会和zfs list保持一致。
2. 对比cron和手动环境的变量差异
虽然你已经设置了PATH,但可能还有其他隐藏的环境变量在影响df的行为。可以做个快速验证:
- 在cron里加一条任务:
* * * * * env > /tmp/cron_env.txt,等一分钟后查看这个文件 - 手动在终端执行:
env > /tmp/shell_env.txt - 对比两个文件,重点看
BLOCKSIZE、LC_ALL、LANG这些变量
如果发现BLOCKSIZE在cron里是512,而手动环境是1024,那就是根源了。你可以直接在脚本开头加上export BLOCKSIZE=1024来统一环境。
3. 直接用zfs list获取数据,彻底绕过df的兼容性问题
既然zfs list的输出本身就是准确的,不如直接用它来提取需要的字段,完全避免df在不同环境下的行为差异。修改脚本的核心逻辑如下:
while read disk used avail ; do echo $disk " " $used " " $avail done < <(zfs list -H -o name,used,avail | grep 'datapool/')
这里的参数说明:
-H:去掉表头行,只输出数据-o name,used,avail:指定只输出存储池名称、已用容量、可用容量三个字段
这种方式比用df更可靠,因为直接从ZFS的原生工具获取数据,不会有文件系统挂载层面的单位转换问题。
4. 确认cron执行的shell是否为bash
FreeBSD默认的cron执行shell是sh,虽然你脚本开头写了#!/usr/bin/env bash,但有些情况下cron可能还是会用sh来执行脚本(比如系统配置的问题)。你可以在脚本开头加一行验证:
echo "Running shell: $0" > /tmp/cron_shell_check.txt
如果发现cron用的是sh,虽然这不一定是当前问题的根源,但可以在cron任务里显式指定bash执行,比如把cron任务写成:
* * * * * /usr/bin/env bash /path/to/your/script.sh
内容的提问来源于stack exchange,提问作者Felix

