
所以,我有一個備份腳本,如下所示:
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 執行。