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_FILEスクリプトexit 1が終了しました。

私たちはあなたの命令が何をしているのかわかりませんがlogging、私が知っている限り、それは書くつもりではありませんでした$LOG_FILE。もしそうなら、このように書くのは少し愚かなことです。ログファイルの確認:$ {LOG_FILE}そこに。

編集する

これで関数を公開したので、loggingここではstring()を使用するのがわかります<<<

では、bashhere-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はその内容を含む電子メールを送信しようとします)。したがって、ENOSPCエラーが原因ですべてのコマンドがwrite(1, ...)失敗する可能性write(2, ...)があり、それが致命的なエラーであると判断した場合は、誤動作または早期終了の可能性があります。

答え2

問題は可能性が最も高いです。

PACKING_EXITCODE=${PIPESTATUS[0]}

有効なシェルコードではありませんが、bash特定のコードです。

Cronは/bin/sh他のコマンドを呼び出しますbash

スクリプトを次から始めることができます。

#!/bin/bash

デフォルトシェルではなく、デフォルトシェルで特定のコードが実行さchmod +x scriptnameれるようにスクリプトを実行可能にします。bashbash

関連情報