删除所有,但在bash最新的X文件 [英] Delete all but the most recent X files in bash
问题描述
有没有一种简单的方法,在pretty标准的UNIX环境下使用bash,运行命令从目录中删除所有,但最新的X文件?
Is there a simple way, in a pretty standard UNIX environment with bash, to run a command to delete all but the most recent X files from a directory?
为了让更多的一个具体的例子中,假设一些cron作业写了一个文件(比如说,一个日志文件或焦油编了备份),以每小时目录。我想办法把另一cron作业运行这将删除该目录中的最旧的文件,直到有不足,比如,5。
To give a bit more of a concrete example, imagine some cron job writing out a file (say, a log file or a tar-ed up backup) to a directory every hour. I'd like a way to have another cron job running which would remove the oldest files in that directory until there are less than, say, 5.
和仅仅是明确的,但只有一个文件present,它应该永远不会被删除。
And just to be clear, there's only one file present, it should never be deleted.
推荐答案
与现有的答案的问题是:
The problems with the existing answers:
- 无法处理文件名含有空格或换行符。
- 在调用解决方案的情况下,
RM
上一个不带引号命令替换直接(RM``...
),还有意想不到的通配的额外的风险。
- inability to handle filenames with embedded spaces or newlines.
- in the case of solutions that invoke
rm
directly on an unquoted command substitution (rm `...`
), there's an added risk of unintended globbing.
wnoise的回答解决了这些问题,但解决的办法是的 GNU 的特异性(和相当复杂的)。
wnoise's answer addresses these issues, but the solution is GNU-specific (and quite complex).
下面是一个务实, POSIX兼容的解决方案随只有一个警告:它不能处理文件名带有嵌入式的换行的 - 但我不T认为,对大多数人真实世界的关注。
Here's a pragmatic, POSIX-compliant solution that comes with only one caveat: it cannot handle filenames with embedded newlines - but I don't consider that a real-world concern for most people.
为了记录在案,这里是为什么它通常不是一个好主意来解析
LS的解释
输出:http://mywiki.wooledge.org/ParsingLsFor the record, here's the explanation for why it's generally not a good idea to parse
ls
output: http://mywiki.wooledge.org/ParsingLsls -tp | grep -v '/$' | tail -n +6 | xargs -I {} rm -- {}
以上就是低效,因为
的xargs
已调用RM
一次每个的文件名。结果
平台的的xargs
可以让你解决这个问题:The above is inefficient, because
xargs
has to invokerm
once for each filename.
Your platform'sxargs
may allow you to solve this problem:如果您有 GNU 的
的xargs
,使用-d的'\\ n'
,使的xargs
考虑每个输入行一个单独的参数,但传递尽可能多的参数作为适合命令行的一次对EM>If you have GNU
xargs
, use-d '\n'
, which makesxargs
consider each input line a separate argument, yet passes as many arguments as will fit on a command line at once:ls -tp | grep -v '/$' | tail -n +6 | xargs -d '\n' rm --
如果您有 BSD 的
的xargs
(包括 OS X ),你可以使用-0
来处理NUL
输入 - 分隔后,先换行转换为NUL
(为0x0
)字符,它也可以通过(典型值),所有文件名的一次的(也将与GNU <工作code>的xargs )If you have BSD
xargs
(including on OS X), you can use-0
to handleNUL
-separated input, after first translating newlines toNUL
(0x0
) chars., which also passes (typically) all filenames at once (will also work with GNUxargs
):ls -tp | grep -v '/$' | tail -n +6 | tr '\n' '\0' | xargs -0 rm --
说明:
-
LS -tp
打印的排序文件系统项目的名称,他们是如何被最近修改,按降序排列(最近首次修改的项目)(-t
),印有一个尾随/
来标记它们(目录-p
)。 -
的grep -v'/ $'
然后从打开的上市会淘汰目录,通过省略(-v
)有一个尾随行/
(/ $
)。- 的买者的:由于的符号链接指向一个目录的在技术上是不是本身就是一个目录,例如符号链接会的不的排除
ls -tp
prints the names of filesystem items sorted by how recently they were modified , in descending order (most recently modified items first) (-t
), with directories printed with a trailing/
to mark them as such (-p
).grep -v '/$'
then weeds out directories from the resulting listing, by omitting (-v
) lines that have a trailing/
(/$
).- Caveat: Since a symlink that points to a directory is technically not itself a directory, such symlinks will not be excluded.
-
xargs的-I {} RM - {}
定义占位符{}
的再presents每输入行的作为一个整体的,所以RM
然后为每个输入行调用一次,但与正确处理嵌入空格的文件名。 -
-
在所有情况下,确保这种情况发生下手任何文件名 -
是没有错的话选项的由RM
。
xargs -I {} rm -- {}
defines placeholder{}
that represents each input line as a whole, sorm
is then invoked once for each input line, but with filenames with embedded spaces handled correctly.--
in all cases ensures that any filenames that happen to start with-
aren't mistaken for options byrm
.
A 变异在原来的问题,的情况下匹配的文件需要处理的个别或收集在一个shell阵列的
A variation on the original problem, in case the matching files need to be processed individually or collected in a shell array:
# One by one, in a shell loop (POSIX-compliant): ls -tp | grep -v '/$' | tail -n +6 | while IFS= read -r f; do echo "$f"; done # One by one, but using a Bash process substitution (<(...), # so that the variables inside the `while` loop remain in scope: while IFS= read -r f; do echo "$f"; done < <(ls -tp | grep -v '/$' | tail -n +6) # Collecting the matches in a Bash *array*: IFS=$'\n' read -d '' -ra files < <(ls -tp | grep -v '/$' | tail -n +6) printf '%s\n' "${files[@]}" # print array elements
这篇关于删除所有,但在bash最新的X文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
- in the case of solutions that invoke
- 在调用解决方案的情况下,