如何删除除最后一个目录以外的所有目录

时间:2018-09-28 08:56:19

标签: bash

我可以用命令获取目录数量

ls -dtr */ | wc -l

但是我该如何专门删除N-1个目录,而保留最新目录呢?

4 个答案:

答案 0 :(得分:4)

与通常对“一堆文件”进行的bash操作一样,您必须意识到空格和换行符的痛苦,这些痛苦和换行符可能合法地出现在文件名中。这些方法打破了基于xargs / for的朴素方法,并且需要一些额外的限制。

许多工具支持-z-0选项,这些选项使用NUL字节作为行分隔符而不是换行符-NUL可能永远不是文件名的一部分。

不幸的是,ls不是其中之一,因此我们必须经过find才能获取最新目录。

find . -maxdepth 1 -mindepth 1 -type d

这将获得当前目录中的所有目录。 (请注意:与您的ls -dtr */相对,这还会查找“隐藏”目录,即以.开头的目录。添加! -name ".*"可以避免这种情况。 )

-maxdepth 1避免了递归,-mindepth 1将父目录(.)排除在列表之外。

find . -maxdepth 1 -mindepth 1 -type d -printf "%T+ %f\0"

这将列出目录及其时间戳,使用NUL而不是换行符进行行分隔。 (NUL永远不能成为文件名的一部分。)

find . -maxdepth 1 -mindepth 1 -type d -printf "%T+ %f\0" | sort -z

这使用NUL而不是换行符对结果进行排序。

find . -maxdepth 1 -mindepth 1 -type d -printf "%T+ %f\0" | sort -z | head -z -n -1

这将使用列表中的最后一个条目(最新目录及其时间戳)使用NUL而不是换行符来获取列表中的最后一个条目(最新目录及其时间戳)。

find . -maxdepth 1 -mindepth 1 -type d -printf "%T+ %f\0" | sort -z | head -z -n -1 | cut -z -d' ' -f 2-

使用NUL代替换行符作为行分隔符和空格作为字段定界符,这将从输出中过滤出第一个字段(时间戳)。

find . -maxdepth 1 -mindepth 1 -type d -printf "%T+ %f\0" | sort -z | head -z -n -1 | cut -z -d' ' -f 2- | xargs -0 rm -rf

使用NUL代替换行符来进行行分隔,这将为每个条目调用rm -rf

答案 1 :(得分:2)

这是一个纯Bash解决方案:

shopt -s nullglob   # Globs that match nothing expand to nothing
shopt -s dotglob    # Globs include files whose names start with '.'

newest_dir=
for sdir in */ ; do
    dir=${sdir%/}               # Remove slash to enable a symlink check
    [[ -L $dir ]] && continue   # Skip symlinks to directories

    if [[ -z $newest_dir ]] ; then
        newest_dir=$dir
    elif [[ $dir -nt $newest_dir ]] ; then
        echo rm -rf  -- "$newest_dir"
        newest_dir=$dir
    else
        echo rm -rf -- "$dir"
    fi
done

它以当前形式仅打印命令以删除旧的子目录。删除echo以使其起作用。

答案 2 :(得分:1)

使用tail

ls -dt */ | tail -n +2 | while read dirName; do rmdir "$dirName"; done

在将-n的{​​{1}}的{​​{1}}选项指定为tail时,它将跳过第一行。

这将列出按日期排序的目录,跳过最近的目录并保留其余的目录,这些目录将被删除。您可以在用例之后将+替换为rmdir

您可以尝试:

rm -rf

输出:

mkdir test && cd test
for i in {1..100}; do mkdir subdir-$i; done
ls -dt */ | tail -n +2 | while read dirName; do rmdir "$dirName"; done
ls

编辑:如果任何目录名称包含换行符,则由于subdir-100 ,该方法将失败。在这种情况下,请参阅@DevSolar的答案以获取更完整的答案。

答案 3 :(得分:0)

很多方法,这是另一种方法。 :)

rm -rf `ls -1dt * | tail -n +2 | tr '\n' ' '`

首先,ls -1dt *仅列出按修改时间排序的所有目录,每行一个。然后tail -n +2删除第一个,最近修改的。然后tr '\n ' '将它们全部放在一行中。然后是rm -rf目录。