所以,我有一个备份脚本,如下所示:
tar -cf "${BACKUP_TAR}" "${LATEST_SUCCESSFUL_BACKUP}" 2>&1 | tee -a "${LOG_FILE}"
local PACKING_EXITCODE=${PIPESTATUS[0]}
if [ ${PACKING_EXITCODE} -eq 0 ]; then
logging 'Packing successful'
else
logging "ERROR: Packing failed! ERROR: ${PACKING_EXITCODE}. Disk space?"
df -h 2>&1 | tee -a "${LOG_FILE}"
logging "Check the log file: ${LOG_FILE}"
set_lockfile 'destroy'
backup_remove_package
exit 1
fi
logging
是一个正确登录到我的日志文件的函数。
logging () {
local now="$(date)"
local logfile=$2
local logfile=${logfile:-$LOG_FILE}
cat <<< "${now} $@" | tee -a "${logfile}"
}
set_lockfile "destroy"` 是一个删除我的锁定文件的函数。
set_lockfile () {
local lockfile_action=$1
local lockfile=$2
local lockfile=${lockfile:-$LOCK_FILE}
if [ "${lockfile_action}" == "create" ]; then
#...
elif [ "${lockfile_action}" == "destroy" ]; then
destroy_lockfile $lockfile
else
logging 'ERROR: Wrong argument for locking file: use create or destroy'
exit 1
fi
}
destroy_lockfile () {
local lockfile=$1
if [ ! -f ${lockfile} ]; then
logging "WARNING: Lockfile ${lockfile} not found!"
else
logging "Removing lockfile ${lockfile}"
rm -f "${lockfile}"
fi
}
backup_remove_package
是删除创建的任何临时文件的函数。
由于磁盘已满,我遇到了打包失败的情况,正如您可以猜测的那样df -h
。
有趣的是备份日志。它指出:
tar: /tmp/backup/20180827T223001.tar: Wrote only 4096 of 10240 bytes
tar: Error is not recoverable: exiting now
Filesystem Size Used Avail Use% Mounted on
/dev/xvda1 788G 788G 0 100% /
devtmpfs 3.9G 60K 3.9G 1% /dev
tmpfs 3.9G 0 3.9G 0% /dev/shm
这意味着,tar
失败了,然后它经历了if
条件,以某种方式跳过了logging "ERROR: ..."
,执行了df -h
并死亡。跳过其余部分。
不知怎的,看起来像是跳过任何功能但运行命令。
从文件调用备份cron.d
。我还没有设置set -e
,所以不会出现错误退出。
有什么想法为什么会发生这种情况吗?
答案1
您的脚本似乎按预期工作。的输出df
显然已完成$LOG_FILE
并exit 1
导致脚本退出。
我们不知道你的logging
命令是做什么的,但据我所知,它并不是要写入$LOG_FILE
.如果是的话,这样写就有点傻了检查日志文件:${LOG_FILE}那里。
编辑
现在您已经发布了该logging
函数,我可以看到它使用了此处字符串 ( <<<
)。
在 中bash
,here-strings 和 here-documents 是使用临时文件实现的(在$TMPDIR
或/tmp
if中$TMPDIR
未定义)。如果文件系统已满,那就可以解释为什么logging
没有输出任何内容。
$ sudo mount -o size=1 -t tmpfs empty /mnt/1
$ yes > /mnt/1/fill-up
yes: standard output: No space left on device
$ TMPDIR=/mnt/1 bash -c 'cat <<< test'
bash: cannot create temp file for here-document: No space left on device
代替:
local now="$(date)"
cat <<< "${now} $@" | tee -a "${logfile}"
只需使用:
printf '%(%FT%T%z)T %s\n' -1 "$*"
printf '%(%FT%T%z)T %s\n' -1 "$*" >> "$logfile"
或者:
local msg
printf -v msg '%(%FT%T%z)T %s' -1 "$*"
printf '%s\n' "$msg"
printf '%s\n' "$msg" >> "$logfile"
(假设$IFS
未设置或以空格开头)
这可以保存临时文件,但也可以避免分叉任何进程或执行任何外部命令(在某些病理条件下也可能失败)(并为您提供更有用的日期格式,请随意适应)。
更一般地说,具有完整 /tmp 和 /var 文件系统的系统是一个瘫痪的系统,您可以预料到很多事情都无法正常工作。
在这里,你很幸运你有日志。文件的磁盘空间是以块的形式分配的(在 ext4 上通常为 4K),这可能就是为什么你在 `$LOG_FILE 中得到一些输出(因为最后一个块是在文件系统变满之前分配的)。
由 cron 运行的脚本也将其 stdout 和 stderr 放在临时文件上(如果它们不为空,则 cron 会尝试发送包含其内容的电子邮件)。因此,任何命令也可能会write(1, ...)
失败write(2, ...)
(带有 ENOSPC 错误),如果它们认为这是致命错误,则可能会导致它们行为不当或提前退出。
答案2
问题很有可能是
PACKING_EXITCODE=${PIPESTATUS[0]}
不是有效的 shell 代码,而是bash
特定的代码。
Cron 调用与/bin/sh
不同的命令bash
。
你可以让你的脚本开始
#!/bin/bash
并使脚本可执行,chmod +x scriptname
以确保bash
特定代码由默认 shell 执行bash
,而不是由默认 shell 执行。