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

관련 정보