Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Bash 删除所有早于X天的文件,但至少保留Y天_Bash_Shell_Command Line_Find - Fatal编程技术网

Bash 删除所有早于X天的文件,但至少保留Y天

Bash 删除所有早于X天的文件,但至少保留Y天,bash,shell,command-line,find,Bash,Shell,Command Line,Find,我有一个脚本,可以从备份目录中删除早于X=21天的DB转储: DB_DUMP_DIR=/var/backups/dbs RETENTION=$((21*24*60)) # 3 weeks find ${DB_DUMP_DIR} -type f -mmin +${RETENTION} -delete 但是,无论出于何种原因,数据库转储作业暂时无法完成,所有转储最终都将被丢弃。因此,作为一种保护措施,我希望至少保留最年轻的Y=7个转储,即使它们全部或部分已超过21天 我在寻找比这个意大利面更优

我有一个脚本,可以从备份目录中删除早于X=21天的DB转储:

DB_DUMP_DIR=/var/backups/dbs
RETENTION=$((21*24*60))  # 3 weeks

find ${DB_DUMP_DIR} -type f -mmin +${RETENTION} -delete
但是,无论出于何种原因,数据库转储作业暂时无法完成,所有转储最终都将被丢弃。因此,作为一种保护措施,我希望至少保留最年轻的Y=7个转储,即使它们全部或部分已超过21天

我在寻找比这个意大利面更优雅的东西:

DB_DUMP_DIR=/var/backups/dbs
RETENTION=$((21*24*60))  # 3 weeks
KEEP=7

find ${DB_DUMP_DIR} -type f -printf '%T@ %p\n' | \  # list all dumps with epoch
sort -n | \                                         # sort by epoch, oldest 1st
head --lines=-${KEEP} |\                            # Remove youngest/bottom 7 dumps
while read date filename ; do                       # loop through the rest
    find $filename -mmin +${RETENTION} -delete      # delete if older than 21 days
done
(这段代码可能有一些小错误——忽略它们。这是为了说明我自己能想出什么,以及为什么我不喜欢它)


编辑:查找选项“-mtime”是一次性的:“-mtime+21”实际上意味着“至少22天”。这总是让我困惑,所以我用-mmin代替。仍然是一次性的,但只需一分钟。

您可以自己完成循环:

t21=$(date -d "21 days ago" +%s)
cd "$DB_DUMP_DIR"
for f in *; do
    if (( $(stat -c %Y "$f") <= $t21 )); then
        echo rm "$f"
    fi
done
t21=$(日期-d“21天前”+%s)
cd“$DB\u DUMP\u DIR”
对于f in*;做

如果($(stat-c%Y“$f”)使用
find
获取所有足以删除的文件,则用
tail
筛选出
$KEEP
最年轻的文件,然后将其余文件传递给
xargs

find ${DB_DUMP_DIR} -type f -printf '%T@ %p\n' -mmin +$RETENTION |
  sort -nr | tail -n +$KEEP |
  xargs -r echo
如果报告的文件列表是要删除的列表,请将
echo
替换为
rm


(我假设所有转储文件的名称中都没有换行。)

您可以使用
-mtime
而不是
-mmin
,这意味着您不必计算一天中的分钟数:

find $DB_DUMP_DIR -type f -mtime +21
您可以使用
stat
命令对文件进行排序,而不是删除它们:

find $DB_DUMP_DIR -type f -mtime +21 | while read file
do
    stat -f "%-10m %40N" $file
done | sort | awk 'NR > 7 {print $2}'
这将列出所有超过21天的文件,但不包括最年轻的7个超过21天的文件

从那里,您可以将其输入到xargs以执行删除操作:

find $DB_DUMP_DIR -type f -mtime +21 | while read file
do
    stat -f "%-10m %40N" $file
done | sort | awk 'NR > 7 {print $2]' | xargs rm
当然,这都是假设你的文件名中没有空格。如果你有,你将不得不采取稍微不同的策略

这也将使七个最年轻的文件保留超过21天。您可能有比这更年轻的文件,并且不想真正保留这些文件。但是,您只需再次运行相同的序列(除了删除
-mtime
参数:

find $DB_DUMP_DIR -type f |  while read file
do
    stat -f "%-10m %40N" $file
done | sort | awk 'NR > 7 {print $2} | xargs rm
您需要查看您的命令以查看格式的选项。这因系统而异。我使用的是OS X。Linux不同


让我们采取一种稍微不同的方法。我尚未对此进行彻底测试,但:

如果所有文件都在同一目录中,并且没有一个文件名包含空格:

ls -t | awk 'NR > 7 {print $0}'
会打印出所有的文件,除了七个最年轻的文件。也许我们可以继续

current_seconds=$(date +%S)   # Seconds since the epoch
((days = 60 * 60 * 24 * 21))  # Number of seconds in 21 days
((oldest_allowed = $current_seconds - $days)) # Oldest allowed file
ls -t | awk 'NR > 7 {print $0}' | stat -f "%Dm %N" $file | while date file
do
    [ $date < $oldest_allowed ] || rm $file
done
current_seconds=$(日期+%S)#自纪元起的秒数
((天=60*60*24*21))#21天内的秒数
((允许的最早时间=$current_seconds-$days))#允许的最早文件
ls-t | awk'NR>7{print$0}'| stat-f“%Dm%N”$file |而日期文件
做
[$date<$OLEST_允许]| | rm$文件
完成
ls…| awk
将删除最年轻的七个。之后,我们可以使用stat获取文件名和日期。由于日期是纪元后几秒,我们必须计算当前时间前21天在纪元前几秒

在那之后,就很简单了。我们看一下文件的日期。如果它比纪元早21天(即,它的时间戳较低),我们可以删除它


正如我所说,我还没有完全测试过这个,但这将删除21天内的所有文件,并且只删除21天内的文件,但始终保留最年轻的七个文件。

我打开第二个答案,因为我有一个不同的解决方案-使用
awk
:只需将时间添加到21天(以秒为单位)句点,减去当前时间并删除负的句点!(在排序并从列表中删除最新的7之后):


这些答案中没有一个对我很有效,所以我采用了切普纳的答案并得出了这个结论,它只是保留了最后的
$KEEP
备份

find ${DB_DUMP_DIR} -printf '%T@ %p\n' | # print entries with creation time
  sort -n |                              # sort in date-ascending order
  head -n -$KEEP |                       # remove the $KEEP most recent entries
  awk '{ print $2 }' |                   # select the file paths
  xargs -r rm                            # remove the file paths

我相信chepner的代码保留了
$KEEP
最老的,而不是最年轻的。

下面是一个BASH函数,应该可以做到这一点。我不能轻易地避免两次调用
find
,但除此之外,这是一次相对成功的调用:

#  A "safe" function for removing backups older than REMOVE_AGE + 1 day(s), always keeping at least the ALWAYS_KEEP youngest
remove_old_backups() {
    local file_prefix="${backup_file_prefix:-$1}"
    local temp=$(( REMOVE_AGE+1 ))  # for inverting the mtime argument: it's quirky ;)
    # We consider backups made on the same day to be one (commonly these are temporary backups in manual intervention scenarios)
    local keeping_n=`/usr/bin/find . -maxdepth 1 \( -name "$file_prefix*.tgz" -or -name "$file_prefix*.gz" \) -type f -mtime -"$temp" -printf '%Td-%Tm-%TY\n' | sort -d | uniq | wc -l`
    local extra_keep=$(( $ALWAYS_KEEP-$keeping_n ))

    /usr/bin/find . -maxdepth 1 \( -name "$file_prefix*.tgz" -or -name "$file_prefix*.gz" \) -type f -mtime +$REMOVE_AGE -printf '%T@ %p\n' |  sort -n | head -n -$extra_keep | cut -d ' ' -f2 | xargs -r rm
}
它采用
backup\u file\u前缀
env变量,或者可以将其作为第一个参数传递,并希望环境变量
始终保持
(要保持的最小文件数)和
删除
(传递到
的天数-mtime
)。它需要一个
gz
tgz
扩展。您可以在评论中看到一些其他假设,主要是出于安全考虑

感谢和(并没有完全回答这个问题)的启发


Happy safe backup management:)

从其他解决方案中给出的解决方案中,我尝试并发现了许多不需要的错误或情况

以下是我最终提出的解决方案:

  # Sample variable values
  BACKUP_PATH='/data/backup'
  DUMP_PATTERN='dump_*.tar.gz'
  NB_RETENTION_DAYS=10
  NB_KEEP=2                    # keep at least the 2 most recent files in all cases

  find ${BACKUP_PATH} -name ${DUMP_PATTERN} \
    -mtime +${NB_RETENTION_DAYS} > /tmp/obsolete_files

  find ${BACKUP_PATH} -name ${DUMP_PATTERN} \
    -printf '%T@ %p\n' | \
    sort -n            | \
    tail -n ${NB_KEEP} | \
    awk '{ print $2 }'   > /tmp/files_to_keep

  grep -F -f /tmp/files_to_keep -v /tmp/obsolete_files > /tmp/files_to_delete

  cat /tmp/files_to_delete | xargs -r rm
这些想法是:

  • 大多数时候,我只想保留不超过NB_保留天数的文件
  • 然而,狗屎发生了,当出于某种原因不再有最近的文件(备份脚本被破坏)时,为了安全起见,我不想删除NB_KEEP more-recent文件(NB_KEEP应该至少为1)
在我的案例中,我每天有2个备份,并将NB_RETENTION_DAYS设置为10(因此,在正常情况下,我通常有20个文件) 人们可能会认为我会这样设置NB_KEEP=20,但事实上,我选择了NB_KEEP=2,这就是为什么:

假设我的备份脚本坏了,我一个月都没有备份。我真的不在乎有20个超过30天的最新文件。至少有一个是我想要的。 然而,能够轻松地识别出问题是非常重要的(显然我的监控系统真的是盲目的,但这是另一点)。而且,让我的备份文件夹的文件比平时少10倍可能会敲响警钟

  # Sample variable values
  BACKUP_PATH='/data/backup'
  DUMP_PATTERN='dump_*.tar.gz'
  NB_RETENTION_DAYS=10
  NB_KEEP=2                    # keep at least the 2 most recent files in all cases

  find ${BACKUP_PATH} -name ${DUMP_PATTERN} \
    -mtime +${NB_RETENTION_DAYS} > /tmp/obsolete_files

  find ${BACKUP_PATH} -name ${DUMP_PATTERN} \
    -printf '%T@ %p\n' | \
    sort -n            | \
    tail -n ${NB_KEEP} | \
    awk '{ print $2 }'   > /tmp/files_to_keep

  grep -F -f /tmp/files_to_keep -v /tmp/obsolete_files > /tmp/files_to_delete

  cat /tmp/files_to_delete | xargs -r rm