while 循环删除所有文件并陷入循环

while 循环删除所有文件并陷入循环

我无法使用 while 循环删除文件,直到保留一定数量的文件。

这就是我所拥有的:

touch while/151234
touch while/152355
touch while/151694
touch while/153699
touch while/156946
NUMSNAPS=$(ls while | awk '{print $1}' | wc -l)
RETAIN=2

while [ "$RETAIN" -le "$NUMSNAPS" ]; do
    OLDEST=$(ls | awk '{print $1}' | head -n 1)
    rm "$OLDEST"
done

我无法使用 find 来删除这些文件,因为这实际上是与另一个第三方命令一起使用的测试。我计划用 DOCTL 查找快照并删除它们,直到剩下某个快照为止。

答案1

您有一个循环,根据两个您从不改变的变量来测试特定条件。我假设您的意思是NUMSNAPS在每次迭代中将值减少一。


zshshell 中,你可以这样做

retain=2

rm -f while/*(DN.Om[retain+1,-1])

删除除$retain最近修改的文件之外的所有常规文件(包括具有隐藏名称的文件)。如果这恰好是数千个文件,您可能需要改用zargs

retain=2

autoload -U zargs
zargs -- while/*(DN.Om[retain+1,-1]) -- rm

如果您想按名称对文件进行排序,请将Om(“按 mtime 时间戳排序,按降序排列”) 替换为On(“按名称排序,按降序排列”)。

显然,您可以从另一个 shell 调用它,而不是zsh使用例如

retain=2

zsh -c 'rm -f $2/*(DN.Om[$1+1,-1])' zsh "$retain" "while"

这还将目录名称和要保留的文件数量传递到内联脚本中,从而更容易合并到现有的非脚本中zsh


bashshell 中,你并不是真的想要解析输出ls。相反,您可能想使用

shopt -s dotglob nullglob

retain=2

set -- while/*

while [ "$#" -gt "$retain" ]; do
    rm -f "$1"
    shift
done

这会将位置参数列表设置为while目录中的文件列表(包括隐藏名称),然后从该列表中删除文件,直到retain列表中只剩下文件为止。

这可以避免文件名尴尬的问题,并且还可以避免ls为每个删除的文件调用一次。

此代码将根据文件名称(而不是上次修改时间戳)删除文件。这似乎是您的代码也试图做的事情。

答案2

但是为什么你不能获得完整的列表并只保留你需要的文件数量呢?例如:

ls -r while | tail -n +${retain} | xargs echo rm

答案3

以下是我将如何修复和改进您的脚本:

#!/bin/bash

touch while/151234
touch while/152355
touch while/151694
touch while/153699
touch while/156946

NUMSNAPS=$(ls -1 while | wc -l)
RETAIN=2

while (( RETAIN < NUMSNAPS )); do
    OLDEST=$(ls -1t while | tail -n 1)
    rm "while/$OLDEST"
    (( --NUMSNAPS ))
done

相关内容