我有一个使用 cron 定期运行的脚本。当这些脚本失败时,我希望收到电子邮件通知。我不希望每次运行并产生任何输出时都收到通知。
因此,我正在使用脚本克罗尼克在 cron 中运行我的作业,这应该意味着只发送错误输出,而不仅仅是任何输出。
但是,在一个脚本中我有这样的命令:
if [ "$(ls -A ${local_backup_location}/nextcloud-data/)" ]; then
# save space by removing diffs older than 6 months
rdiff-backup --remove-older-than 6M --force ${local_backup_location}/nextcloud-data/ || echo "[$(date "+%Y-%m-%d %T")] No existing nextcloud data backup"
fi
旨在ls -A ${local_backup_location}/nextcloud-data/
测试目录是否为空。我的问题是这个命令似乎会产生被识别为错误输出 cronic 的输出。 Cronic 将错误定义为任何非跟踪错误输出或非零结果代码。例如:
Cronic detected failure or error output for the command:
/usr/local/sbin/run_backup
RESULT CODE: 0
ERROR OUTPUT:
appdata_ocgcv9nemegb
files_external
flow.log
flow.log.1
__groupfolders
.htaccess
index.html
nextcloudadmin
nextcloud-db.bak
nextcloud.log
nextcloud.log.1
.ocdata
rdiff-backup-data
Test_User
updater.log
updater-ocgcv9nemegb ]
custom
gitea-db.sql
log ]
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
100 365 0 0 100 365 0 302 0:00:01 0:00:01 --:--:-- 303
100 365 0 0 100 365 0 165 0:00:02 0:00:02 --:--:-- 165
100 365 0 0 100 365 0 113 0:00:03 0:00:03 --:--:-- 113
100 365 0 0 100 365 0 86 0:00:04 0:00:04 --:--:-- 86
100 365 0 0 100 365 0 70 0:00:05 0:00:05 --:--:-- 70
100 365 0 0 100 365 0 58 0:00:06 0:00:06 --:--:-- 0
100 365 0 0 100 365 0 50 0:00:07 0:00:07 --:--:-- 0
100 365 0 0 100 365 0 44 0:00:08 0:00:08 --:--:-- 0
100 365 0 0 100 365 0 39 0:00:09 0:00:09 --:--:-- 0
100 365 0 0 100 365 0 37 0:00:09 0:00:09 --:--:-- 0
100 10.4M 0 10.4M 100 365 1016k 34 0:00:10 0:00:10 --:--:-- 2493k
100 11.6M 0 11.6M 100 365 1128k 34 0:
00:10 0:00:10 --:--:-- 3547k
STANDARD OUTPUT:
Maintenance mode enabled
Deleting increment at time:
<snip>
那么为什么该命令ls -A ${local_backup_location}/nextcloud-data/
在这种情况下会产生错误输出,以及如何防止这种情况发生?另一种可靠的方法来测试目录是否为空是可以接受的,但我还想解释为什么该命令似乎会产生错误输出。
编辑:添加 Cronic 标准输出set -ex
一些评论者要求提供非常长的实际整个脚本,但 Cronic 报告了脚本的实际标准输出,我set -ex
在脚本的顶部使用。错误输出在调用后立即发生,ls -A /mnt/reos-storage-2/backups/nextcloud-data/
这就是为什么我相信错误输出是此命令的结果。
+ rdiff-backup --ssh-no-compression /var/www/nextcloud /mnt/reos-storage-2/backups/nextcloud/
+ ls -A /mnt/reos-storage-2/backups/nextcloud-data/
+ [ 67cf481e-62a3-1039-8bf2-05805d214bca
<removed>
appdata_ocgcv9nemegb
<removed>
<removed>
<removed>
<removed>
files_external
flow.log
flow.log.1
__groupfolders
.htaccess
index.html
<removed>
<removed>
nextcloudadmin
nextcloud-db.bak
nextcloud.log
nextcloud.log.1
.ocdata
<removed>
<removed>
rdiff-backup-data
<removed>
Test_User
<removed>
updater.log
updater-ocgcv9nemegb ]
+ rdiff-backup --remove-older-than 6M --force /mnt/reos-storage-2/backups/nextcloud-data/
+ date +%Y-%m-%d %T
+ echo [2021-04-21 03:23:38] Starting nextcloud data backup
答案1
+ [ 67cf481e-62a3-1039-8bf2-05805d214bca <已删除> [...] 更新程序日志 更新程序-ocgcv9nemegb]
这里,这是一个命令。它在set -x
/输出中分成多行xtrace
,因为 / 输出ls
包含换行符。 (Bash 会打印出带有一些引号的内容,而 Dash 则不会。)
默认情况下,xtrace
输出会发送到 stderr,与常规错误输出相同,Cronic 尝试通过查看+
行开头的标记来将它们分开xtrace
。这里失败了,它认为文件名是常规的错误输出。
cronic 的作用基本上是这样的:
PATTERN="^${PS4:0:1}\\+${PS4:1}" if grep -aq "$PATTERN" $TRACE then ! grep -av "$PATTERN" $TRACE > $ERR
禁用xtrace
是解决这个问题的一种方法,但这样做会很遗憾,因为 cronic 很好地支持它。
相反,最好使用其他方法来检查目录是否为空。
与 保持一致ls -A
,您可以通过管道输出来wc
计算那里的字符:
if [ "$(ls -A "${local_backup_location}/nextcloud-data/" | wc -c)" -gt 0 ]; then
echo "directory not empty"
fi
或者grep
:
if ls -A "${local_backup_location}/nextcloud-data/" | grep -q .; then
echo "directory not empty";
fi
检查目录是否为空可以在 shell 本身内以其他方式完成,但处理所有极端情况可能会很麻烦。参见例如 便携式检查空目录
答案2
如果$gitea_backup_dir
不存在,或者ls
以任何方式让人不高兴,ls
则会向 写入一条错误消息STDERR
。
2>/dev/null
您可以通过附加到命令来丢弃整个错误流。
恕我直言,更好的方法是:
if ([[ -d "$gitea_backup_dir" ]] && \
[[ $(stat --format="%h" "$gitea_backup_dir") -gt 2 ]] ) ; then
echo "Nonempty"
else
echo "Empty"
fi
首先检查目录是否存在,然后查看目录中的硬链接数量(目录中文件和子目录条目的数量)是否大于2(每个目录至少有2个条目:.
和..
)。