如何创建 Bash 脚本来管理临时文件并进行自动归档和清理?

如何创建 Bash 脚本来管理临时文件并进行自动归档和清理?

想要一个使用 Bash 脚本在 Linux 环境中管理临时文件的解决方案。

  • 如果文件位于根文件夹中并且在 10 天内保持未修改状态,请将文件移至子文件夹并添加时间戳前缀(例如“2022-01-01_文件名”)。
  • 如果先前移动的文件被修改,则应将其返回到根文件夹,并且不带时间戳前缀。
  • 删除自上次修改日期起 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 +10适用于 11 天或更早的文件,并且-mtime -10适用于不到 10 天的文件,因此此处未涵盖 24 小时期限的文件(最后修改时间为 10 到 11 天前的文件)。
  • 在第二个命令中,如果存在名称中find没有或包含字符的文件,则将无法按预期工作。例如,如果是,则将成为并且对于,则给出。_$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 没有意义,因为 bash 没有比 sh 更有用的扩展名,这对这里有帮助;您自己的代码中没有任何内容是特定于 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将移入ab不是将其重命名为。因此要事先进行检查,但这也引入了 TOCTOU 比赛; GNU 实现有一个有帮助的选项。's在其冲突处理中具有类似的竞争条件;传递到GNU 系统至少可以帮助缓解其中的一些问题。bb[ -dmv-Tzshzmv-o -nTzmv

(注意:我没有测试过任何代码)。

相关内容