如何根据文件名中的日期删除旧备份?

Jou*_*uda 7 scripting bash shell-script file-management

我有一个像这样命名的每日备份:

yyyymmddhhmm.zip // pattern
201503200100.zip // backup from 20. 3. 2015 1:00
Run Code Online (Sandbox Code Playgroud)

我正在尝试创建一个脚本来删除超过 3 天的所有备份。该脚本还应该能够删除文件夹中与模式不匹配的所有其他文件(但脚本中会有一个开关来禁用它)。

为了确定文件年龄,我不想使用备份时间戳,因为其他程序也会对文件进行操作,并且可能会被篡改。

在以下帮助下:删除 UNIX 中超过 5 天的文件(文件名中的日期,而不是时间戳) 我得到:

#!/bin/bash

DELETE_OTHERS=yes
BACKUPS_PATH=/mnt/\!ARCHIVE/\!backups/
THRESHOLD=$(date -d "3 days ago" +%Y%m%d%H%M)

ls -1 ${BACKUPS_PATH}????????????.zip |
  while read A DATE B FILE
  do
     [[ $DATE -le $THRESHOLD ]] && rm -v $BACKUPS_PATH$FILE
  done

if [ $DELETE_OTHERS == "yes" ]; then
    rm ${BACKUPS_PATH}*.* // but I don't know how to not-delete the files matching pattern
fi
Run Code Online (Sandbox Code Playgroud)

但它一直在说:

rm: missing operand
Run Code Online (Sandbox Code Playgroud)

问题出在哪里以及如何完成脚本?

ter*_*don 8

代码中的第一个问题是您正在解析ls. 这意味着它很容易损坏,例如,如果您的文件或目录名称中有任何空格。您应该使用 shell globbing 或find代替。

更大的问题是您没有正确读取数据。您的代码:

ls -1 | while read A DATE B FILE
Run Code Online (Sandbox Code Playgroud)

永远不会填充$FILE。的输出ls -1只是文件名列表,因此,除非这些文件名包含空格,否则只会read填充您提供的 4 个变量中的第一个。

这是您的脚本的工作版本:

#!/usr/bin/env bash

DELETE_OTHERS=yes
BACKUPS_PATH=/mnt/\!ARCHIVE/\!backups
THRESHOLD=$(date -d "3 days ago" +%Y%m%d%H%M)

## Find all files in $BACKUPS_PATH. The -type f means only files
## and the -maxdepth 1 ensures that any files in subdirectories are
## not included. Combined with -print0 (separate file names with \0),
## IFS= (don't break on whitespace), "-d ''" (records end on '\0') , it can
## deal with all file names.
find ${BACKUPS_PATH} -maxdepth 1 -type f -print0  | while IFS= read -d '' -r file
do
    ## Does this file name match the pattern (13 digits, then .zip)?
    if [[ "$(basename "$file")" =~ ^[0-9]{12}.zip$ ]]
    then
        ## Delete the file if it's older than the $THR
        [ "$(basename "$file" .zip)" -le "$THRESHOLD" ] && rm -v -- "$file"
    else
        ## If the file does not match the pattern, delete if 
        ## DELETE_OTHERS is set to "yes"
        [ $DELETE_OTHERS == "yes" ] && rm -v -- "$file"
    fi
done
Run Code Online (Sandbox Code Playgroud)