tar 失敗後,腳本退出而不處理錯誤

tar 失敗後,腳本退出而不處理錯誤

所以,我有一個備份腳本,如下所示:

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_FILEexit 1導致腳本退出。

我們不知道您的logging命令是做什麼的,但據我所知,它並不是要寫入$LOG_FILE.如果是的話,這樣寫就有點傻了檢查日誌檔案:${LOG_FILE}那裡。

編輯

現在您已經發布了該logging函數,我可以看到它使用了此處字串 ( <<<)。

在 中bash,here-strings 和 here-documents 是使用臨時檔案實現的(在$TMPDIR/tmpif中$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 執行。

相關內容