임시 파일을 관리하고 보관 및 정리를 자동화하는 Bash 스크립트를 만드는 방법은 무엇입니까?

임시 파일을 관리하고 보관 및 정리를 자동화하는 Bash 스크립트를 만드는 방법은 무엇입니까?

Bash 스크립트를 사용하여 Linux 환경에서 임시 파일을 관리하는 솔루션을 원합니다.

  • 파일이 루트 폴더에 있고 10일 동안 수정되지 않은 상태로 남아 있는 경우 파일을 하위 폴더로 이동하고 타임스탬프 접두사(예: "2022-01-01_filename")를 추가합니다.
  • 이전에 이동한 파일이 수정된 경우 타임스탬프 접두사 없이 루트 폴더로 반환되어야 합니다.
  • 마지막 수정일로부터 90일 이내에 수정되지 않은 파일을 삭제합니다.

내가 시도한 것은 다음과 같습니다. 몇 가지 오류가 발생했지만 해당 오류를 수정한 후에는 아무 작업도 수행되지 않는 것 같습니다. 아무튼, 몇 시간 동안 고민한 끝에 수정된 날짜별로 정렬할 수 있는 파일 관리자를 사용하는 것이 좋겠다는 생각이 들었습니다.

#!/bin/bash

FOLDER="$HOME/tmp"
SUBFOLDER="$HOME/tmp/old"

[ ! -d "$FOLDER" ] && mkdir -p "$FOLDER"
[ ! -d "$SUBFOLDER" ] && mkdir -p "$SUBFOLDER"

find "$FOLDER" -maxdepth 1 -type f -mtime +10 -exec sh -c '
  for file do
    timestamp=$(date +"%Y-%m-%d")
    new_filename="$SUBFOLDER/$timestamp_$(basename "$file")"
    mv "$file" "$new_filename"
  done' sh {} +

find "$SUBFOLDER" -type f -mtime -10 -exec sh -c '
  for file do
    new_filename="$FOLDER/${file#*_}"
    mv "$file" "$new_filename"
  done' sh {} +

find "$SUBFOLDER" -type f -mtime +90 -exec rm {} \;
chmod +x /path/to/script.sh
crontab -e
0 0 * * * /path/to/script.sh

답변1

이 코드에는 몇 가지 문제가 있습니다(일부는 사소한 문제입니다).

  • FOLDER이러한 변수와 변수를 환경으로 내보내지 않으므로 SUBFOLDER에서 시작한 호출에서는 사용할 수 없습니다.shfind
  • 디렉토리는 ~/tmp비공개여야 하며 mkdir -m 700 ~/tmp.
  • 이것은 [ -d ... ] || mkdir ...전형적인 TOCTOU 경쟁 모드입니다. 사전 검사가 필요하지 않습니다 mkdir -p.
  • $(...)임의의 파일 이름과 함께 사용할 수 없도록 후행 줄 바꿈을 제거합니다.
  • 오류 처리를 수행하지 않습니다. 오류가 있는 경우 최소한 종료 상태를 보고할 수 있습니다.
  • 반복할 때마다 오늘 날짜를 계산할 필요가 없습니다.
  • 이는 -mtime +1011일 이상 된 파일에 적용되고 -mtime -1010일 미만의 파일에 적용되므로 24시간 기간의 파일(10~11일 전에 마지막으로 수정된 파일)은 여기에서 다루지 않습니다.
  • find두 번째 명령에서는 이름에 문자가 없거나 포함된 파일이 있으면 예상대로 작동하지 않습니다. 예를 들어, 만약 그렇다면, 그러면 될 것이고, for, then이 주어집니다._$SUBFOLDER_$file/home/you/tmp/old/old-file$new_file_name/home/you/tmp//home/you/tmp/old/old-file/home/your_home/tmp/old/2023-10-01_file/home/your_home/tmp/home/tmp/old/2023-10-01_file
  • mv이미 존재하는 대상 파일 (디렉토리 또는 디렉토리에 대한 심볼릭 링크)이 처리되지 않는 등의 충돌 .
  • -maxdepth표준 find술어가 아닙니다.

그리고 zsh:

#! /bin/zsh -
autoload zmv || exit
mkdir -pm 700 -- ~/tmp && cd -P -- ~/tmp && mkdir -p old || exit

today=${(%):-%D{%F}} ret=0

# move 10 day old or older regular files
zmv '*(#qND.m+9)' 'old/${today}_$f' || ret=$?

# move back regular files that are less than 10 day old.
zmv 'old/<1900-2100>-<1-12>-<1-31>_(*)(#qND.m-10)' '$1' || ret=$?

# remove regular files that are 91 day old or older
rm -f old/*(ND.m+90) || ret=$?

exit $ret

( shbash에는 sh보다 더 유용한 확장 기능이 없기 때문에 bash를 사용할 필요가 없습니다. 이는 여기서 도움이 될 것입니다. 자신의 코드에는 bash와 관련된 것이 없으며 대신 .sh스크립트에 확장 기능을 제공합니다 .bash.)

#! /bin/sh -
mkdir -pm 700 -- ~/tmp && cd -P -- ~/tmp && mkdir -p old || exit

TODAY=$(date +%Y-%m-%d) || exit
export TODAY

ret=0
# move 10 day old or older regular files
find . ! -name . -prune -type f -mtime +9 -exec sh -c '
  ret=0
  for file do
    file=${file#./}
    mv -i -- "$file" "old/${TODAY}_$file" || ret=$?
  done
  exit "$ret"' {} + || ret=$?

# move back regular files that are less than 10 day old.
LC_ALL=C find old/. ! -name . -prune \
  -name '[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]_*' \
  -type f -mtime -10 -exec sh -c '
  ret=0
  for file do
    new=${file#*/./}
    new=${new#*_}
    if [ -d "$new" ]; then
      printf>&2 "%s\n" "$new is a directory"
      ret=1
    else
      mv -i -- "$file" "$new" || ret=$?
    fi
  done
  exit "$ret"' {} + || ret=$?

# remove regular files that are 91 day old or older
find old/ -mtime +90 -type f -exec rm -f {} + || ret=$?

exit "$ret"

-i충돌을 처리하기 위해 여기에서 사용되는 옵션입니다 mv. 대화형으로 실행하면 파일을 덮어쓸 때 메시지가 표시됩니다. cronstdin is 로 실행 하면 /dev/null덮어쓰기가 거부되지만 불행하게도 실패 시 반환되지 않습니다. -nGNU 옵션 도 참조하세요 mv(그러나 실패도 반환하지 않음).

디렉터리(또는 디렉터리에 대한 심볼릭 링크)로 존재하는 경우 이름이 바뀌지 않고 mv a b이동됩니다 . 따라서 미리 확인하세요. 하지만 이는 또한 TOCTOU 경쟁을 도입합니다. GNU 구현에는 유용한 옵션이 있습니다. 의 충돌 처리에 있어 비슷한 경쟁 조건이 있습니다. GNU 시스템으로 전달하면 이러한 문제 중 적어도 일부를 완화하는 데 도움이 됩니다.abbb[ -dmv-Tzshzmv-o -nTzmv

(참고: 저는 어떤 코드도 테스트하지 않았습니다.)

관련 정보