我用来find
删除符合某些条件的文件:
find -type f [more criteria] -delete
一般来说,这工作得很好,但我遇到了其他用户创建的子目录的问题:据我所知,是否允许我删除文件取决于我对父目录的权限。因此,对于另一个用户创建的子目录中包含的文件,上面的命令会失败:
fbrucker@host /tmp $ ls -lh
total 4,0K
drwxrwxr-x 2 root root 4,0K Jun 15 11:44 foo/
fbrucker@host /tmp $ ls -lh foo/
total 0
-rw-rw-r-- 1 fbrucker fbrucker 0 Jun 15 11:44 a
-rw-rw-r-- 1 root root 0 Jun 15 11:44 b
fbrucker@host /tmp $ find -type f -delete
find: cannot delete ‘./foo/b’: Permission denied
find: cannot delete ‘./foo/a’: Permission denied
没关系,我无法删除这些文件,但缺少权限会导致find
以非零状态退出。我想避免这种情况。
在尝试删除无法删除的文件之前,如何过滤掉它们?
请注意,只需过滤掉错误消息即可不是对我来说足够了,因为这仍然会给我留下非零退出代码。另外,完全忽略退出代码对我来说不起作用,因为我确实想捕获其他错误(我真正的find
命令更复杂,例如find /somedir -type f -delete
我想不是/somedir
忽略不存在时引发的错误)。
我知道它对find
文件的权限进行了测试(例如,,,-perm
),但我认为它们不适用于此处。例如,-readable
-writable
fbrucker@host /tmp $ find -type f -writable
./foo/a
即使我无法删除,foo/a
因为我没有必要的权限foo
。
我正在寻找类似-deletable
测试的东西,但似乎不存在。
答案1
是的,您需要对父目录具有写访问权限,并且如果该目录已设置位t
,则必须是该目录或要取消链接的文件的所有者,并且所有这些都假设 ACL 等其他安全控制未到位并且文件所在的 FS 不是只读的,这使得是可删除的检查比较复杂。
for -readable
// -writable
(-executable
非标准)find
可以只使用相应的access(R_OK/W_OK/X_OK)
系统调用,但没有等效的for取消链接一份文件。
使用 GNU find
4.9.0 或更高版本,您可以使用以下命令进行近似:
find . -depth -type d -writable '(' -uid "$EUID" -o ! -perm -o=t ')' -print0 |
find -files0-from - -mindepth 1 -maxdepth 1 -type f -delete
zsh
(还假设像或bash
这样的shell设置$EUID
。如果没有,请使用"$(id -u)"
)。
这会将您拥有的文件留在t
您不拥有的 -bit 目录中,您需要单独处理这些文件:
find . -depth -type d -writable ! -uid "$EUID" -perm -o=t -print0 |
find -files0-from - -mindepth 1 -maxdepth 1 -type f -uid "$EUID" -delete
您可能还希望设置pipefail
shell 选项以便能够通过第一个find
.
使用旧版本的 GNU find
,您始终可以执行以下操作:
find . -depth -type d -writable '(' -uid "$EUID" -o ! -perm -o=t ')' -exec sh -c '
exec find "$@" -mindepth 1 -maxdepth 1 -type f -delete
' sh {} +
如果重点是忽略由于访问权限而取消链接文件的失败,您可以这样做:
set -o pipefail
find . -depth -type f -print0 |
perl -l -0ne '
unless (unlink($_) || $!{EACCES}) {
warn "$_: $!\n";
$ret = 1;
}
END {exit $ret}'
答案2
一种解决方法是使用-exec rm {} \;
代替-delete
,因为find
会忽略调用的退出代码-exec
。