for*_*rin 15 directory find rm
我想递归删除文件夹中一段时间内未访问的a
所有文件,子文件夹中的所有文件除外b
。
find a \( -name b -prune \) -o -type f -delete
Run Code Online (Sandbox Code Playgroud)
但是,我收到一条错误消息:
find: -delete 操作会自动打开 -depth,但 -prune 在 -depth 生效时什么也不做。如果您想继续,只需明确使用 -depth 选项。
添加-depth
会导致b
包含所有文件,这绝不能发生。
任何人都知道一种安全的方法来使这项工作?
les*_*ana 17
一种方法是使用-exec rm
代替-delete
.
find a \( -name b -prune \) -o -type f -exec rm {} +
Run Code Online (Sandbox Code Playgroud)
或者使用-not -path
代替-prune
:
find a -not -path "*/b*" -type f -delete
Run Code Online (Sandbox Code Playgroud)
解释为什么-prune
与 碰撞-delete
:
当您尝试使用-delete
with时, find 会抱怨,-prune
因为-delete
暗示-depth
和-depth
使-prune
无效。
观察使用和不使用 find 的行为-depth
:
$ find foo/
foo/
foo/f1
foo/bar
foo/bar/b2
foo/bar/b1
foo/f2
Run Code Online (Sandbox Code Playgroud)
不能保证单个目录中的顺序。但是可以保证目录在其内容之前被处理。foo/
在 any之前foo/*
和foo/bar
any 之前注意foo/bar/*
。
这可以用 反转-depth
。
$ find foo/ -depth
foo/f2
foo/bar/b2
foo/bar/b1
foo/bar
foo/f1
foo/
Run Code Online (Sandbox Code Playgroud)
请注意,现在都foo/*
出现在foo/
. 与foo/bar
.
更多解释:
-prune
防止 find 下降到目录中。换句话说,-prune
跳过目录的内容。在您的情况下,-name b -prune
意味着当 find 到达具有名称的目录时b
,它将跳过包含所有子目录的目录。-depth
使 find 在目录本身之前处理目录的内容。这意味着当 find 开始处理目录条目时,b
它的内容已经被处理了。因此-prune
是无效的-depth
。-delete
意味着-depth
它可以先删除内容,然后删除空目录。-delete
拒绝删除非空目录。替代方法的说明:
find a -not -path "*/b*" -type f -delete
Run Code Online (Sandbox Code Playgroud)
这可能会也可能不会更容易记住。
此命令仍会下降到目录中b
并处理其中的每个文件,只是为了-not
拒绝它们。如果目录b
很大,这可能是一个性能问题。
-path
与-name
. -name
仅匹配(文件或目录的)名称,而-path
匹配整个路径。例如观察路径/home/lesmana/foo/bar
。-name bar
将匹配,因为名称是bar
. -path "*/foo*"
将匹配,因为字符串/foo
在路径中。-path
在使用它之前,您应该了解一些复杂的问题。阅读手册页find
了解更多详情。
请注意,这并非 100% 万无一失。有可能出现“误报”。上面写命令的方式将跳过任何具有名称以b
(正)开头的父目录的文件。但它也会跳过名称开头的任何文件,b
而不管树中的位置如何(误报)。这可以通过编写比 更好的表达式来解决"*/b*"
。这留给读者作为练习。
我假设您使用a
andb
作为占位符,而真实姓名更像是allosaurus
and brachiosaurus
。如果您brachiosaurus
使用 代替,b
那么误报的数量将大大减少。
至少误报将不能删除,所以这将是不一样悲惨。此外,您可以通过首先运行命令而检查误报-delete
(但请记住放置隐含的-depth
)并检查输出。
find a -not -path "*/b*" -type f -depth
Run Code Online (Sandbox Code Playgroud)