unix下如何删除超过60个文件的文件夹中的文件?

unix下如何删除超过60个文件的文件夹中的文件?

我想在 cronjob 中放置一个脚本,该脚本将在特定时间运行,如果文件计数超过 60,它将从该文件夹中删除最旧的文件。后进先出。我努力了,

#!/bin/ksh  
for dir in /home/DABA_BACKUP  
do  
    cd $dir  
    count_files=`ls -lrt | wc -l`   
    if [ $count_files -gt 60 ];  
    then  
        todelete=$(($count_files-60))  
        for part in `ls -1rt`  
        do  
            if [ $todelete -gt 0 ]  
            then  
                rm -rf $part  
                todelete=$(($todelete-1))  
            fi  
        done  
    fi
done   

这些都是每天保存并命名为 的备份文件backup_$date。这个可以吗?

答案1

不,一方面它会破坏包含换行符的文件名。它也比必要的更复杂,并且具有以下所有危险解析 ls

更好的版本是(使用 GNU 工具):

#!/bin/ksh  
for dir in /home/DABA_BACKUP/*
do
    ## Get the file names and sort them by their
    ## modification time
    files=( "$dir"/* );
    ## Are there more than 60?
    extras=$(( ${#files[@]} - 60 ))
    if [ "$extras" -gt 0 ]
    then
    ## If there are more than 60, remove the first
    ## files until only 60 are left. We use ls to sort
    ## by modification date and get the inodes only and
    ## pass the inodes to GNU find which deletes them
    find dir1/ -maxdepth 1 \( -inum 0 $(\ls -1iqtr dir1/ | grep -o '^ *[0-9]*' | 
        head -n "$extras" | sed 's/^/-o -inum /;' ) \) -delete
    fi
done

请注意,这假设所有文件都位于同一文件系统上,如果不是,则可能会产生意外结果(例如删除错误的文件)。如果有多个硬链接指向同一个 inode,它也无法正常工作。

答案2

#! /bin/zsh -
for dir (/home/DABA_BACKUP/*) rm -f $dir/*(Nom[61,-1])

为了zsh-无知;-):

  • for var (list) cmd:循环的简短版本for var in list; do cmd; done(让人想起perl语法)。
  • $dir:zsh变量不需要像在其他 shell 中那样加zsh引号明确的 splitglob运算符所以不做隐式分割+全局参数扩展时。
  • *(...): 与全局限定符:
  • N: nullglob: 当不匹配时,glob 会扩展为空,而不是引发错误。
  • m:将生成的文件放在修改时间(最小的在前)。
  • [61,-1]:从该有序列表中选择倒数第 61 个。

所以基本上删除了除 60 个最年轻的文件之外的所有文件。

答案3

要获取要删除的最旧条目的列表(从而保留 60 个最新条目):

ls -t | tail -n +61

请注意,您的方法的主要问题仍然需要在这里解决:如何处理带有换行符的文件,以防万一;否则你可以使用(替换你相当复杂的程序):

cd /home/DABA_BACKUP || exit 1
ls -t | tail -n +61 | xargs rm -rf


注意:因为看起来你有每日备份您也许还可以使用基于文件日期和的方法find;如:

find /home/DABA_BACKUP -mtime +60 -exec ls {} +

ls在仔细检查正确操作后,该命令将被适当的命令替换rm)。

答案4

如果您知道文件都名为 backup_*,则应该将其包含在 ls 命令中,这样您只处理这些文件,而不处理意外进入目录的文件。然后ls用在管道中,每行只列出1个文件,然后只计数,不需要排序,所以

count_files=$(ls -U backup_* | wc -l)

for part in $(ls -rt backup_*);do
    rm -rf "$part"
    todelete=$(($todelete-1))
    if [[ $todelete -eq 0 ]]; then
        break
    fi
done

相关内容