如何删除给定目录中最旧的目录?

如何删除给定目录中最旧的目录?

可能的重复:
用于移动最旧文件的 shell 脚本?

我有一个备份目录,存放x其他需要备份的目录。我需要在另一个目录移动到备份之前运行的东西,它将检查目录数量是否达到x,如果达到,它将删除最旧的目录。

它应该在脚本中完成bash

答案1

ls解析is的输出不可靠的

相反,使用find来定位目录并按sort时间戳对它们进行排序。例如:

IFS= read -r -d $'\0' line < <(find . -maxdepth 1 -type d -printf '%T@ %p\0' \ 
    2>/dev/null | sort -z -n)
file="${line#* }"
# do something with $file here

这一切到底是在做什么?

首先,这些find命令查找当前目录 ( .) 中的所有目录,但不查找当前目录 ( -maxdepth 1) 的子目录中的所有目录,然后打印出:

  • 时间戳
  • 空间
  • 文件的相对路径
  • 空字符

时间戳很重要。的格式%T@说明-printf符分为T,表示文件的“上次修改时间”(mtime) 和@,表示“自 1970 年以来的秒数”,包括小数秒。

空格只是一个任意的分隔符。文件的完整路径是为了方便我们稍后引用它,而 NULL 字符是终止符,因为它是文件名中的非法字符,因此可以让我们确定已到达文件路径的末尾。文件。

我已包含在内2>/dev/null,以便排除用户无权访问的文件,但会抑制有关它们被排除的错误消息。

该命令的结果find是当前目录中所有目录的列表。该列表通过管道传送到sort,指示:

  • -z将 NULL 视为行终止符而不是换行符。
  • -n按数字排序

由于 1970 年以来的秒数总是增加,因此我们需要时间戳是最小数字的文件。第一个结果sort将是包含最小编号时间戳的行。剩下的就是提取文件名。

find,管道的结果sort通过流程替代to read,它被读取为标准输入上的文件。

read在我们将变量设置为空的上下文中IFS,这意味着空格不会被不恰当地解释为分隔符。read被告知-r,它禁用转义扩展,并且-d $'\0',它使行尾分隔符为 NULL,与我们的find,sort管道的输出相匹配。

第一个数据块代表最旧的目录路径,前面带有时间戳和空格,被读入变量line。下一个,参数替换与表达式 一起使用#*,它只是将从字符串开头到第一个空格(包括空格)的所有字符替换为空。这会去掉修改时间戳,只留下文件的完整路径。

此时,文件名已存储在中$file,您可以使用它执行任何您喜欢的操作,包括rm -rf "$file".

难道就没有更简单的方法吗?

不。更简单的方法是有缺陷的。

如果您使用ls -t并通过管道传递到,tail您将在文件名中带有换行符的文件上中断。如果rm $(anything)名称中包含空格的文件将导致损坏。如果rm "$(anything)"名称中带有尾随换行符的文件将导致损坏。

也许在特定情况下,您确信更简单的方法就足够了,但如果可以避免的话,您永远不应该将这样的假设写入脚本中。

编辑

#!/usr/bin/env bash

dir="$1"
min_dirs=3

[[ $(find "$dir" -maxdepth 1 -type d | wc -l) -ge $min_dirs ]] &&
IFS= read -r -d $'\0' line < <(find "$dir" -maxdepth 1 -printf '%T@ %p\0' 2>/dev/null | sort -z -n)
file="${line#* }"
ls -lLd "$file"

问题的更完整解决方案,因为它首先检查目录计数。

答案2

你可以使用类似下面的东西:

#!/bin/sh    
keep=3

while [ `ls -1 | wc -l` -gt $keep ]; do
    oldest=`ls -c1 | head -1`
    echo "remove $oldest"
    rm -rf $oldest
done

使用 but 可能会find . -type d -maxdepth 1更好ls。这取决于您用于目录的命名模式。如果它们自然地按名称正确排序,您可以使用find,sortheadtail来获取最旧/最新的目录。该ls方法使用 ctime 属性进行排序。

答案3

尝试使用:

rm $(ls -t1 | tail -n 1)

相关内容