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、here-string ( ) が使用されていることがわかります<<<

ではbash、ヒアストリングとヒアドキュメントは一時ファイルを使用して実装されます ($TMPDIRまたはが定義されていない/tmp場合は)。 いっぱいになったファイルシステムであれば、何も出力されなかった$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]}

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

/bin/shCron はとは異なるでコマンドを呼び出しますbash

スクリプトを次のように始めることもできます

#!/bin/bash

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

関連情報