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
에서 시작한 호출에서는 사용할 수 없습니다.sh
find
- 디렉토리는
~/tmp
비공개여야 하며mkdir -m 700 ~/tmp
. - 이것은
[ -d ... ] || mkdir ...
전형적인 TOCTOU 경쟁 모드입니다. 사전 검사가 필요하지 않습니다mkdir -p
. $(...)
임의의 파일 이름과 함께 사용할 수 없도록 후행 줄 바꿈을 제거합니다.- 오류 처리를 수행하지 않습니다. 오류가 있는 경우 최소한 종료 상태를 보고할 수 있습니다.
- 반복할 때마다 오늘 날짜를 계산할 필요가 없습니다.
- 이는
-mtime +10
11일 이상 된 파일에 적용되고-mtime -10
10일 미만의 파일에 적용되므로 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
( sh
bash에는 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
. 대화형으로 실행하면 파일을 덮어쓸 때 메시지가 표시됩니다. cron
stdin is 로 실행 하면 /dev/null
덮어쓰기가 거부되지만 불행하게도 실패 시 반환되지 않습니다. -n
GNU 옵션 도 참조하세요 mv
(그러나 실패도 반환하지 않음).
디렉터리(또는 디렉터리에 대한 심볼릭 링크)로 존재하는 경우 이름이 바뀌지 않고 mv a b
이동됩니다 . 따라서 미리 확인하세요. 하지만 이는 또한 TOCTOU 경쟁을 도입합니다. GNU 구현에는 유용한 옵션이 있습니다. 의 충돌 처리에 있어 비슷한 경쟁 조건이 있습니다. GNU 시스템으로 전달하면 이러한 문제 중 적어도 일부를 완화하는 데 도움이 됩니다.a
b
b
b
[ -d
mv
-T
zsh
zmv
-o -nT
zmv
(참고: 저는 어떤 코드도 테스트하지 않았습니다.)