我无法使用 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
在每次迭代中将值减少一。
在zsh
shell 中,你可以这样做
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
。
在bash
shell 中,你并不是真的想要解析输出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