chmod对数千个文件的递归权限


16

这是关于递归“更改”的更一般的问题。

我有此脚本,有时需要在具有几十万个文件的文件夹中递归更改权限。每天都会在该文件夹中添加新文件,但是已经存在的文件已经设置了权限,并且它们不会更改。

我的问题是...当我打电话时

chmod 775。-R

它会尝试为已设置正确权限的文件设置权限,还是仅为没有正确权限的新文件设置权限?

尽管“新”文件只有几千个,并且它应该相当快地完成其权限,但似乎总是需要花费很多时间才能通过脚本中的此命令。

我已经看过chmod的手册页,但是在这种情况下似乎没有提及任何内容。

如果chmod事先没有检查权限,我是否应该开始考虑将“查找”与“ chmod”结合使用?


3
我想知道检查权限并更改它们(如果它们不正确)是否真的比直接将它们设置为正确的值要慢。
lgeorget13年

1
如果有人偶然发现此问题并想要find + chmod命令,则为:find。!-烫发775 -print0 | xargs -0 -I {} chmod 775 {}
Titi Dumi

@lgeorget,所以您说使用find | chmod较慢?而不是仅仅修改所有内容。(对不起,您的评论不明白)。欢呼声
Titi Dumi

以我的拙见,它可能会慢一些,因为它需要分两个过程并将第一个过程的输出重定向到第二个过程,但是我不确定。这取决于设置权限所花费的时间,该时间可能并不重要,因为在inode中修改权限只有3个字节。
lgeorget13年

1
@depquid此处的主要性能问题是将数据读取到磁盘缓存中。第一次运行后,所有内容都在磁盘缓存中(除非内存太少),因此您正在测试某种性能,而这在实际情况中并不是瓶颈。
Hauke Laging

Answers:


9

chmod可能会或可能不会更改已设置为所需文件的权限,但是如果没有,则仍需要检查它们以查看其当前权限是什么[0]。有成千上万个文件,我认为这都不重要。该时间最有可能由工具stat处理每个文件花费。

您可以尝试find检查比上次运行更新的文件或需要运行的文件chmod,但是我认为速度不会提高很多。

如果可能的话,您也许可以将新文件作为“保存”区域放到一个单独的目录中。然后,您可以在chmodTHAT目录(其中只有新文件)中,mv其余文件也都包含在其中。那应该快得多,但是不幸的是,它不适用于每个应用程序。

[0]即使它确实尝试设置不需要任何更改的文件的权限,底层文件系统也可能不会对该请求执行任何操作,因为这是不必要的。


感谢那。我将尝试查找| chmod版本,看看是否可以使事情更快。如果没有,我将尝试按照您的建议修改脚本以实现“持有”文件夹。
Titi Dumi 2013年

您无法获得速度改进的原因是,必须同时为ctime和访问权限读取inode。
Hauke Laging

10

查找/ chmod优化

双方findchmod要读

  1. 所有目录条目
  2. 所有这些条目的索引节点

首先读取所有条目,然后读取所有inode(在旋转的磁盘上),可能会提高性能,因为这样磁盘头就不会在目录和inode之间移动。由于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不时运行。将此目录放在单独的卷上可能会有所帮助。您可以尝试使用不同的文件系统或文件系统设置(例如,不同的inode大小)。


只要您不在NFSv4挂载上,ACL就很好。
ostrokach '16

在docker容器中find,该解决方案使我的时间增加了一倍chmod
Nathan ReinstateMonica Arthur,

8

假设使用的chmodGNU coreutils软件包在Ubuntu 12.10。

chmod 775 . -Rfchmodat不管权限是否需要更改,都针对找到的每个文件执行系统调用。我通过检查代码并使用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因为发现给出了选择的东西更多的控制版本。


1

显示[source](1),它chmod(1)总是尝试设置模式,然后再次使用[fstatat(2)](2)进行检查。

通过[fts(3)](3)处理文件,该文件必须事先“统计”所有遍历的文件系统对象以构建其数据树。

Unixlore的特色是[nice article](4),chmod(1)它在时间上与find/ xargs方法相对应:后者以幅度取胜。

这里的命令行适应了原始问题:

find . -print0 | xargs -0 chmod 775

两个原因:

  1. 通过两个进程之间的管道将文件系统遍历与文件操作分离开,甚至可以在不同的内核上运行。

    1. fts(3)操作被最小化,因为xargs(1)“拉平”了目录树。

是的:您绝对应该使用find/ xargs。一个简单的解决方案。

其他选项:

  • 播放[umask](5)和写入新文件的进程的源代码。

  • 如果您使用的是Linux,则您的系统可能已启用 inotify内核子系统。在这种情况下,您可以通过[inotifywait(1)](6)编写高效的解决方案脚本。


旁注:除非您要对文件执行权限,否则建议将调用修改为:

find . -type f -print0 | xargs -0 chmod 664
find . -type d -print0 | xargs -0 chmod 775

编者注:不允许在该帖子中添加两个以上的链接,也不能对其他帖子发表评论。我将这些URL留在这里,希望一些有足够信誉的心胸开阔的用户将它们放回文本中并删除此段。


吸磁盘缓存find . -printf ""

这可能会加快以下chmod操作的执行速度,但是取决于可用的内存和I / O负载。所以它可能行得通,或者不行。解耦遍历(find)和chmod操作已经提供了缓存,因此启动缓存可能是多余的。

  1. https + lingrok.org / xref / coreutils / src / chmod.c#process_file
  2. https + linux.die.net / man / 2 / fstatat
  3. https + linux.die.net / man / 3 / fts
  4. http + www.unixlore.net / articles / speeding-up-bulk-file-operations.html
  5. https + en.wikipedia.org / wiki / Umask
  6. https + linux.die.net / man / 1 / inotifywait

0

您是否考虑过将创建文件的过程更改为以0775模式创建的过程?查看环境中的umask值-0002可能会有所帮助。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.