该目录包含具有不同扩展名的文件。我想删除除最后 5 个文件之外的所有扩展名为 .gz、zx、ext4 的文件。我可以列出所有这些文件
ls -l | grep '\.gz\|xz\|ext4$'
我可以只显示其中最旧的 5 个:
ls -l | grep '\.gz\|xz\|ext4$' | head -5
或者列出最后 5 个文件:
ls -l | grep '\.gz\|xz\|ext4$' | tail -5
但我不知道如何删除除上述命令中列出的这 5 个文件之外的所有文件。
答案1
如果通常的排序顺序没问题(即文件按日期命名),并且您的 shell 支持数组,则可以使用它们来避免使用时的常见注意事项ls
:
F=(./*.{gz,xz,ext4}) # list files
G=("${F[@]:5}") # pick all but the first five to another array
G=("${F[@]:0:${#F[@]}-5}") # or pick all but the last five
rm -- "${G[@]}" # remove them
zsh
本身可以按日期排序,因此这会将匹配的文件抓取到一个数组中,并按修改时间排序
F=(./*.(gz|xz|ext4)(Om))
((Om)
最新的放在最后,(om)
最新的放在前面。)按上述方式处理数组。
当然,如果你需要按修改日期排序,就不能使用zsh
和知道你的文件名很好,一个简单的ls -t | tail -n +6
就可以了。
(tail -n +6
从第六行开始打印,即跳过前五行。一开始我对此有一个偏差。)
使用 GNU ls,我认为我们可以要求它引用文件名来为 shell 创建合适的输入,然后用输出填充数组:
eval "F=($(ls -t --quoting-style=shell-always ./*.{xz,gz}))"
但这需要相信这一点,ls
并且 shell 同意如何解释引号。
答案2
ls -1 | grep '\.gz$\|xz$\|ext4$' | tail -n +6 | xargs rm
注意事项:您的文件不应包含空格/引号。
set -f; set ./*.[gx]z ./*.ext4; [ "$#" -gt 5] && shift 5; rm -f "$@"
以下内容适用于任何类型的文件名:
td="`mktemp`" \
find . -maxdepth 1 -type f \( -name \*.[gx]z -o -name \*.ext4 \) -exec sh -c '
[ ! -s "$td" ] && [ "$#" -gt 5 ] && { shift 5; echo >> "$td"; }
rm -f "$@"
' x {} +
rm "$td"
答案3
你快到了。
使用长选项格式指定所需的行数,然后将其取反。 (相反的逻辑可以与 一起使用tail
)。
head --lines=3
从头部打印三行
head --lines=-3
从头部打印除最后三个之外的内容
head
这是一个使用 a和一个名为的八行文件的示例f
$ cat f
line 1
line 2
line 3
line 4
line 5
line 6
line 7
line 8
$ head -3 f
line 1
line 2
line 3
$ head --lines=3 f
line 1
line 2
line 3
$ head --lines=-3 f
line 1
line 2
line 3
line 4
line 5
在开始删除文件之前检查这部分是否产生了您想要的内容。
长选项并不是严格必需的,但它没有必须向后兼容 tail 和 head 命令的演变的遗留问题,而且我发现它更容易记住。
head -n-3
与长选项等效head --lines=-3 f
见下文
$ head -3 f #originally
line 1
line 2
line 3
$ head -n3 f #
line 1
line 2
line 3
$ head -n+3 f
line 1
line 2
line 3
$ head -n-3 f
line 1
line 2
line 3
line 4
line 5
$
答案4
以下命令将列出除最后 5 个文件之外的所有文件:
ls -l | grep '\.gz\|xz\|ext4$' | head -n `expr \`ls | grep '\.gz\|xz\|ext4$' | wc -l\` - 4`
您应该能够将其转换为命令来轻松删除文件。