
そこで、次のようなバックアップ スクリプトを用意しました。
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
、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/sh
Cron はとは異なるでコマンドを呼び出しますbash
。
スクリプトを次のように始めることもできます
#!/bin/bash
特定のコードがデフォルトのシェルではなく によって実行されるchmod +x scriptname
ようにするには、 を使用してスクリプトを実行可能にします。bash
bash