这是关于递归“chmoding”的更普遍的问题。
我有这个脚本,在某些时候需要在包含数十万个文件的文件夹中递归地更改权限。该文件夹中每天都会添加新文件,但已有的文件已设置权限并且不会更改。
我的问题是...当我打电话时
chmod 775 。 -R
它是否尝试为已设置正确权限的文件设置权限,或者仅为没有正确权限的新文件设置权限?
尽管“新”文件只有几千个并且它应该相当快地执行其权限,但似乎总是需要很长时间才能在脚本中通过此命令。
我查看了 chmod 的手册页,但似乎没有提及有关此情况的任何内容。
如果 chmod 没有事先检查权限,我是否应该开始考虑将“find”与“chmod”结合起来?
答案1
查找/chmod优化
两者都find
必须chmod
阅读
- 所有目录条目
- 所有这些条目的索引节点
通过首先读取所有条目,然后读取所有索引节点(在旋转磁盘上),您可能会获得性能改进,因为这样磁盘头不会在目录和索引节点之间移动。作为chmod
是愚蠢的(正如其他答案之一所解释的)它应该find
只被调用。但即便如此,在第一个索引节点写入之前读取所有索引节点可能会有所帮助(假设您有足够的可用 RAM 用于磁盘缓存)。我建议这样:
find . -printf "" # reading the file names only
find . ! -perm 775 -printf "" # reading all the inodes (file names are cached)
find . ! -perm 775 -exec chmod 775 + # writing to the cache without reading from disk
好的解决方案:ACL
好的解决方案可能完全不同:如果文件是在此目录中创建的(并且不是从其他位置移动的),那么 ACL 可以即时完成这项工作。您只需在父目录上设置默认 ACL。
通过文件系统优化可以实现进一步的改进。如果是ext3/ext4那么你可能会e2fsck -D
时不时地运行一下。也许将此目录放在单独的卷上会有所帮助。您可以尝试不同的文件系统或文件系统设置(例如不同的索引节点大小)。
答案2
假设使用chmod
来自GNU coreutils 包在 Ubuntu 12.10 上。
chmod 775 . -R
对其找到的每个文件执行fchmodat
系统调用,无论权限是否需要更改。我通过检查代码并使用strace chmod 775 . -R
(下面的片段)列出实际行为来确认这一点。
newfstatat(4, "d", {st_mode=S_IFREG|0666, st_size=0, ...}, AT_SYMLINK_NOFOLLOW) = 0
fchmodat(4, "d", 0775) = 0
newfstatat(4, "c", {st_mode=S_IFREG|0666, st_size=0, ...}, AT_SYMLINK_NOFOLLOW) = 0
fchmodat(4, "c", 0775) = 0
newfstatat(4, "a", {st_mode=S_IFREG|0666, st_size=0, ...}, AT_SYMLINK_NOFOLLOW) = 0
fchmodat(4, "a", 0775) = 0
newfstatat(4, "b", {st_mode=S_IFREG|0666, st_size=0, ...}, AT_SYMLINK_NOFOLLOW) = 0
fchmodat(4, "b", 0775) = 0
fchmodat
在每个文件上运行有几个缺点
- 如果更改大量文件,额外的系统调用可能会变得很重要。
find
//通过仅xargs
更改chmod
需要更改的文件,其他人提到的方法可能会更快。 - 调用
fchmodat
改变每个文件的文件状态修改(ctime)。这将导致每个文件/索引节点每次都会更改,并且可能会导致过多的磁盘写入。可以使用挂载选项来停止这些多余的写入。
一个简单的实验显示了直接发生的 ctime 变化chmod
auser@duncow:/tmp/blah.test$ ls -lc
total 0
-rwxrwxr-x 1 laptop laptop 0 Jun 18 18:17 a
-rwxrwxr-x 1 laptop laptop 0 Jun 18 18:17 b
-rwxrwxr-x 1 laptop laptop 0 Jun 18 18:17 c
-rwxrwxr-x 1 laptop laptop 0 Jun 18 18:17 d
auser@duncow:/tmp/blah.test$ chmod 775 . -R
auser@duncow:/tmp/blah.test$ ls -lc
total 0
-rwxrwxr-x 1 laptop laptop 0 Jun 18 18:25 a
-rwxrwxr-x 1 laptop laptop 0 Jun 18 18:25 b
-rwxrwxr-x 1 laptop laptop 0 Jun 18 18:25 c
-rwxrwxr-x 1 laptop laptop 0 Jun 18 18:25 d
但这并没有改变find
//几分钟后xargs
chmod
auser@duncow:/tmp/blah.test$ date
Tue Jun 18 18:27:27 BST 2013
auser@duncow:/tmp/blah.test$ find . ! -perm 775 -print0 | xargs -0 -I {} chmod 775 {}
auser@duncow:/tmp/blah.test$ ls -lc
total 0
-rwxrwxr-x 1 laptop laptop 0 Jun 18 18:25 a
-rwxrwxr-x 1 laptop laptop 0 Jun 18 18:25 b
-rwxrwxr-x 1 laptop laptop 0 Jun 18 18:25 c
-rwxrwxr-x 1 laptop laptop 0 Jun 18 18:25 d
我总是倾向于使用find
//版本xargs
,chmod
因为 find 可以更好地控制选择内容。
答案3
chmod
可能会或可能不会更改已设置为您想要的文件的权限,但如果没有,仍然需要检查它们以查看其当前权限是什么[0]。对于数十万个文件,我认为这两种方式都不重要;时间很可能花在工具stat
检查每个文件上。
您可以尝试使用find
检查比上次运行更新的文件或需要chmod
运行的文件,但我认为您不会获得太大的速度提升。
如果您的脚本可能的话,您也许可以首先将新文件放入一个单独的目录中,作为“保留”区域。然后你可以chmod
在那个目录(只有新文件)中,将mv
它们与其余的文件放在一起。这应该会快得多,但不幸的是并不适用于每个应用程序。
[0] 即使它确实尝试设置不需要任何更改的文件的权限,底层文件系统可能不会对该请求执行任何操作,因为这是不必要的。
答案4
您是否考虑过更改创建文件的进程以使用 0775 模式创建文件?查看环境中的 umask 值 - 0002 可能会有所帮助。