Linux ext4 在备份/恢复错误后恢复文件和目录访问权限

msz*_*rlo 10 linux filesystems ext4

我有点搞砸了我的个人目录的备份rsync(可能是因为我在 NTFS 文件系统上备份):所有文件都在这里,但所有文件和目录访问权限都是 777。我想知道是否有一个神奇的实用程序可以递归更改:

  • 从 777 到 755 的目录。
  • 从 777 到 644 的常规文件。我家里没有很多可执行文件,所以我可以稍后手动管理。
  • 保持其他文件(链接,其他任何东西?)不变。

在 shell 中做很容易,但需要几个小时......

附属问题:关于在 NTFS 上正确备份 linux 目录层次结构的任何建议(使用rsync或其他)。

har*_*ymc 16

标准推荐的解决方案是直截了当的:

find . -type d -exec chmod 0755 "{}" \+
find . -type f -exec chmod 0644 "{}" \+
Run Code Online (Sandbox Code Playgroud)

这会将尽可能多的文件名作为参数附加到单个命令,直至系统的最大命令行长度。如果行超过此长度,该命令将被多次调用。

如果你想为每个文件调用一次命令,你可以这样做:

find . -type d -exec chmod 0755 "{}" \;
find . -type f -exec chmod 0644 "{}" \;
Run Code Online (Sandbox Code Playgroud)

  • `\;` 方式太慢了,我的基准测试已经运行了 5 多分钟,相比之下 [`\+` 大约 14 秒](https://superuser.com/a/1462081/83694)。我建议从您的答案中删除“\;”。 (5认同)
  • `+` 不是特殊的 shell;没有必要逃避它。 (5认同)
  • @Deltik:我仍然希望答案全面,但我明确表示这是许多文件的首选方法。 (3认同)

小智 15

chmod -R a=,u+rwX,go+rX $DIR 似乎工作正常,并且很可能是最快的,无论您怎么看。

(我使用 进行了检查strace,对于每个文件/目录只进行一次 fchmodat()系统调用——对于 644 的文件和 755 的目录)。

诀窍是X许可,记录在 中man chmod,它的作用类似于x仅用于目录 - 您想要的区别。

什么是没有记录的是我的猜想,他们将在同一顺序应用为指定他们,而不是仅仅在一些随机的顺序,而是与几个变种反复试验使我确信,他们确实在顺序运行给定的,所以我我很确定这总是会像这样工作。

我应该提到这是在 Linux 上,尽管粗略阅读 chmod 的 BSD 联机帮助页表明它也应该在那里工作。


Del*_*tik 10

我对sitaram 的回答Peter Cordes 的评论Fanatique 的回答harrymc 的回答进行了基准测试,但这个回答有最快的方法

平均值:

  • Deltik的答案* - 7.480秒
    *感谢彼得·科德斯暗示的并行
  • sitaram 的回答 – 12.962 秒(比最佳慢 73.275%)
  • Peter Cordes 的评论 – 14.414 秒(比最佳速度慢 92.685%)
  • Fanatique 的回答 – 14.570 秒(比最佳慢 94.772%)
  • harrymc 的更新答案 – 14.791 秒(比最佳速度慢 97.730%)
  • harrymc 的原始答案 – 1061.926 秒(比最佳慢 14096.113%)

完整统计汇总:

Author              N      min     q1      median  q3      max     mean    stddev
------------------  --     ------- ------- ------- ------- ------- ------- --------
Deltik              10     7.121   7.3585  7.4615  7.558   8.005   7.4804  0.248965
sitaram             10     12.651  12.803  12.943  13.0685 13.586  12.9617 0.276589
Peter Cordes        10     14.096  14.2875 14.375  14.4495 15.101  14.4136 0.269732
Fanatique           10     14.219  14.512  14.5615 14.6525 14.892  14.5697 0.211788
harrymc (updated)   10     14.38   14.677  14.8595 14.9025 15.119  14.791  0.21817
harrymc (original)  1      1061.93 1061.93 1061.93 1061.93 1061.93 1061.93 N/A
Run Code Online (Sandbox Code Playgroud)

Deltik 的命令,采用基准格式:

find "$(pwd)" -type d | xargs -P4 chmod 755 & \
find "$(pwd)" -type f | xargs -P4 chmod 644 & 等待

sitaram 的命令,采用基准格式:

chmod -R a=,u+rwX,go+rX "$(pwd)"

Peter Cordes 的命令,采用基准格式:

找到 "$(pwd)" \( -type d -exec chmod 755 {} + \) \
           -o \( -type f -exec chmod 644 {} + \)

Fanatique 的命令,基准格式:

find "$(pwd)" -type d -print0 | xargs -0 chmod 755;\
find "$(pwd)" -type f -print0 | xargs -0 chmod 644

harrymc 的更新命令,采用基准格式:

find "$(pwd)" -type d -exec chmod 755 {} + ; \
find "$(pwd)" -type f -exec chmod 644 {} +

harrymc 的原始命令,基准格式:

find "$(pwd)" -type d -exec chmod 755 {} \; ; \
find "$(pwd)" -type f -exec chmod 644 {} \;

由于chmod每种文件类型有四个并行进程,我的命令是最快的。这允许多个 CPU 内核运行chmod,从而将瓶颈移至内核 I/O 线程或磁盘。

西塔拉姆的指挥部是亚军,因为一切都在chmod指挥部内完成。与其他答案相比,这大大减少了开销,因为:

  • 文件只需要扫描一次(类似于做一个find而不是两个),并且
  • 不需要创建子进程。

然而,这个命令是最不灵活的,因为它依赖于一个技巧,涉及常规文件和目录之间可执行位的不同含义。

Peter Cordes 的注释使用一个find命令,可以防止目录条目的双重查找。文件越多,这种改进就越大。它仍然有创建子chmod进程的开销,这就是为什么它比chmod-only 解决方案慢很多。

在 Fanatique 的命令和 harrymc 的更新命令之间,通过find管道输入xargs( find | xargs) 的速度更快,因为结果流是异步处理的。将找到的结果发送到并发处理,而不是find暂停其查找行为。 (空字节分隔符 ( ) 似乎不影响运行时间。)-execxargs
find -print0 | xargs -0

harrymc 的原始命令太慢了,因为chmod每个文件和文件夹都需要按顺序执行新命令的开销。


在测试设置中,1001 个目录中包含 1000002 个常规文件:

root@demo:~# echo {0..999} | xargs mkdir -p
root@demo:~# find -type d -exec bash -c "cd {}; echo {0..999} | xargs touch" \;
root@demo:~# find | wc -l
1001003
root@demo:~# find -type d | wc -l
1001
root@demo:~# find -type f | wc -l
1000002

我将所有文件和文件夹设置为具有777权限,例如问题的初始条件。

然后,我对命令进行了十次基准测试,每次都在运行测试之前恢复对777with的权限chmod -R 0777 "$(pwd)"

通过OUTPUT表示包含每个基准命令输出的文件,我使用以下方法计算了平均时间:

bc <<< "scale=3; ($(grep real OUTPUT | grep -Po '(?<=m).*(?=s)' | xargs | sed 's/ /+/g'))/10"
Run Code Online (Sandbox Code Playgroud)

Deltik 答案的基准测试结果

root@demo:~# for i in {0..9} ; 做 chmod -R 0777 "$(pwd)" ; 时间 { 找到 "$(pwd)" -type d | xargs -P4 chmod 755 & find "$(pwd)" -type f | xargs -P4 chmod 644 & 等待; }; 完毕
[1] 9791
[2] 9793
[1]- 完成查找 "$(pwd)" -type d | xargs -P4 chmod 755
[2]+ 完成查找 "$(pwd)" -type f | xargs -P4 chmod 644

真正的 0m7.634s
用户 0m2.536s
系统 0m23.384s
[1] 9906
[2] 9908
[1]- 完成查找 "$(pwd)" -type d | xargs -P4 chmod 755
[2]+ 完成查找 "$(pwd)" -type f | xargs -P4 chmod 644

真正的 0m7.443s
用户 0m2.636s
系统 0m23.106s
[1] 10021
[2] 10023
[1]- 完成查找 "$(pwd)" -type d | xargs -P4 chmod 755
[2]+ 完成查找 "$(pwd)" -type f | xargs -P4 chmod 644

真正的 0m8.005s
用户 0m2.672s
系统 0m24.557s
[1] 10136
[2] 10138
[1]- 完成查找 "$(pwd)" -type d | xargs -P4 chmod 755
[2]+ 完成查找 "$(pwd)" -type f | xargs -P4 chmod 644

真正的 0m7.480s
用户 0m2.541s
系统 0m23.699s
[1] 10251
[2] 10253
[1]- 完成查找 "$(pwd)" -type d | xargs -P4 chmod 755
[2]+ 完成查找 "$(pwd)" -type f | xargs -P4 chmod 644

真正的 0m7.397s
用户 0m2.558s
系统 0m23.583s
[1] 10366
[2] 10368
[1]- 完成查找 "$(pwd)" -type d | xargs -P4 chmod 755
[2]+ 完成查找 "$(pwd)" -type f | xargs -P4 chmod 644

真正的 0m7.482s
用户 0m2.601s
系统 0m23.728s
[1] 10481
[2] 10483
[1]- 完成查找 "$(pwd)" -type d | xargs -P4 chmod 755
[2]+ 完成查找 "$(pwd)" -type f | xargs -P4 chmod 644

真正的 0m7.679s
用户 0m2.749s
系统 0m23.395s
[1] 10596
[2] 10598
[1]- 完成查找 "$(pwd)" -type d | xargs -P4 chmod 755
[2]+ 完成查找 "$(pwd)" -type f | xargs -P4 chmod 644

真正的 0m7.243s
用户 0m2.583s
系统 0m23.400s
[1] 10729
[2] 10731
[1]- 完成查找 "$(pwd)" -type d | xargs -P4 chmod 755
[2]+ 完成查找 "$(pwd)" -type f | xargs -P4 chmod 644

真正的 0m7.320s
用户 0m2.640s
系统 0m23.403s
[1] 10844
[2] 10847
[1]- 完成查找 "$(pwd)" -type d | xargs -P4 chmod 755
[2]+ 完成查找 "$(pwd)" -type f | xargs -P4 chmod 644

真正的 0m7.121s
用户 0m2.490s
系统 0m22.943s

平均时间:7.480 秒

sitaram 答案的基准结果

root@demo:~# for i in {0..9} ; 做 chmod -R 0777 "$(pwd)" ; 时间 chmod -R a=,u+rwX,go+rX "$(pwd)" ; 完毕

真正的 0m12.860s
用户 0m0.940s
系统 0m11.725s

真正的 0m13.059s
用户 0m0.896s
系统 0m11.937s

真正的 0m12.819s
用户 0m0.945s
系统 0m11.706s

真正的 0m13.078s
用户 0m0.855s
系统 0m12.000s

真正的 0m12.653s
用户 0m0.856s
系统 0m11.667s

真正的 0m12.787s
用户 0m0.820s
系统 0m11.834s

真正的 0m12.651s
用户 0m0.916s
系统 0m11.578s

真正的 0m13.098s
用户 0m0.939s
系统 0m12.004s

真正的 0m13.586s
用户 0m1.024s
系统 0m12.372s

真正的 0m13.026s
用户 0m0.976s
系统 0m11.910s

平均时间:12.962 秒

Peter Cordes 评论的基准测试结果

root@demo:~# for i in {0..9} ; 做 chmod -R 0777 "$(pwd)" ; time find "$(pwd)" \( -type d -exec chmod 755 {} + \) -o \( -type f -exec chmod 644 {} + \) ; 完毕

真正的 0m14.096s
用户 0m1.455s
系统 0m12.456s

真正的 0m14.492s
用户 0m1.398s
系统 0m12.897s

真正的 0m14.309s
用户 0m1.518s
系统 0m12.576s

真正的 0m14.451s
用户 0m1.477s
系统 0m12.776s

真正的 0m15.101s
用户 0m1.554s
系统 0m13.378s

真正的 0m14.223s
用户 0m1.470s
系统 0m12.560s

真正的 0m14.266s
用户 0m1.459s
系统 0m12.609s

真正的 0m14.357s
用户 0m1.415s
系统 0m12.733s

真正的 0m14.393s
用户 0m1.404s
系统 0m12.830s

真正的 0m14.448s
用户 0m1.492s
系统 0m12.717s

平均时间:14.414 秒

Fanatique 答案的基准测试结果

root@demo:~# for i in {0..9} ; 做 chmod -R 0777 "$(pwd)" ; 时间 { 找到“$(pwd)” -type d -print0 | xargs -0 chmod 755;find "$(pwd)" -type f -print0 | xargs -0 chmod 644;}; 完毕

真正的 0m14.561s
用户 0m1.991s
系统 0m13.343s

真正的 0m14.521s
用户 0m1.958s
系统 0m13.352s

真正的 0m14.696s
用户 0m1.967s
系统 0m13.463s

真正的 0m14.562s
用户 0m1.875s
系统 0m13.400s

真正的 0m14.609s
用户 0m1.841s
系统 0m13.533s

真正的 0m14.892s
用户 0m2.050s
系统 0m13.630s

真正的 0m14.291s
用户 0m1.885s
系统 0m13.182s

真正的 0m14.843s
用户 0m2.066s
系统 0m13.578s

真正的 0m14.219s
用户 0m1.837s
系统 0m13.145s

真正的 0m14.503s
用户 0m1.803s
系统 0m13.419s

平均时间:14.570 秒

harrymc 更新答案的基准测试结果

root@demo:~# for i in {0..9} ; 做 chmod -R 0777 "$(pwd)" ; 时间 { find "$(pwd)" -type d -exec chmod 755 {} + ; find "$(pwd)" -type f -exec chmod 644 {} + ; }; 完毕

真正的 0m14.975s
用户 0m1.728s
系统 0m13.050s

真正的 0m14.710s
用户 0m1.586s
系统 0m12.979s

真正的 0m14.644s
用户 0m1.641s
系统 0m12.872s

真正的 0m14.927s
用户 0m1.706s
系统 0m13.036s

真正的 0m14.867s
用户 0m1.597s
系统 0m13.086s

真正的 0m15.119s
用户 0m1.666s
系统 0m13.259s

真正的 0m14.878s
用户 0m1.590s
系统 0m13.098s

真正的 0m14.852s
用户 0m1.681s
系统 0m13.045s

真正的 0m14.380s
用户 0m1.603s
系统 0m12.663s

真正的 0m14.558s
用户 0m1.514s
系统 0m12.899s

平均时间:14.791 秒

harrymc 原始答案的基准测试结果

由于这个命令有多慢,我只运行了一次基准测试。

root@demo:~# for i in {0..0} ; 做 chmod -R 0777 "$(pwd)" ; 时间{ find "$(pwd)" -type d -exec chmod 755 {} \; ; find "$(pwd)" -type f -exec chmod 644 {} \; ; }; 完毕

真正的 17m41.926s
用户 12m26.896s
系统 4m58.332s

耗时:1061.926 秒

  • +1:良好而全面的分析。 (2认同)