我想以编程方式修复 Linux 系统上驻留在
/home
下的每个用户主目录中的文件的所有权。来自 https://serverfault.com/a/146709/75044 下面的脚本似乎很理想,除了一些用户不在 /etc/passwd
中,因为他们是外部身份验证的。
经过外部身份验证的用户确实有与其主目录关联的 uid 和 gid。从
uid
命令生成的外部身份验证用户 gid
和 id
与 ls -ln
各自的组和用户 ID 不匹配。由于清理输出,我最初没有发现这一点。正在执行映射,因此我认为正确执行此操作的唯一方法是利用目录列表中的 uid
和 gid
。
我们如何从每个用户主目录获取并使用
/etc/passwd
和 uid
,而不是依赖于 gid
,然后递归地将相同的 uid 和 gid 所有权应用于各自主目录中的对象?
#!/bin/bash
while IFS=':' read -r login pass uid gid uname homedir comment; do
if [[ "$homedir" = **/home/** ]]; then
if [ -d "$homedir" ]; then
echo chown -R $uid:$gid "$homedir";
fi
fi
done < /etc/passwd
经过外部身份验证的示例用户将拥有一个用户所在的主目录
/home
drwx------+ 3 DOMAIN\user DOMAIN\DOMAIN USERS 4096 Jan 1 1969 user
但是它的 uid/gid 格式看起来像:
drwx------+ 3 12345 01234 4096 Jan 1 1969 user
来自
id
的输出(uid/gid 与目录列表不匹配):
$ id DOMAIN\\user
uid=2000234(DOMAIN) gid=2000349(DOMAIN\domain users) groups=2056789(DOMAIN\domain users) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
$ stat -c "%n %u:%g" /home/user/
/home/user/ 12345:01234
我认为使用 uid 和 gid 解析用户名和组名会更容易获取和应用。
本地用户示例如下:
drwx------. 4 1000 1000 4096 Jul 21 02:04 user2
drwx------. 4 user2 user2 4096 Jul 21 02:04 user2
$ id user2
uid=1000(user2) gid=1000(user2) groups=1000(user2),4(adm),190(systemd-journal)
编辑
另一种选择是在
/home
中列出文件,通过 stat
提供并将权限应用于那些不匹配的文件。仅更改组的示例是
find /home -maxdepth 1
但我们不想在列表中包含 /home
stat -c %g
针对主目录并设置为变量 $GID
find \! -gid $GID -exec chown :$GID {} \;
如果主目录的子文件或文件夹的 $GID 不匹配,请修复它
像下面这样的不起作用就足够了
find . -exec sh -c '
for f do
GID=$(stat -c %g)
chown :$GID $f
' find-sh {} \;
假设所有主目录的所有者和组与相应的用户匹配,您可以将所有包含的子目录和文件的所有权设置为相同的值。
请注意,可能有些文件或目录故意具有不同的所有者或组。盲目更改所有者或组可能会破坏其他用户或应用程序的访问权限。
此(未经测试的)命令将显示将所有者和组 ID 递归更改为从主目录获取的值的命令:
for i in /home/*/
do
echo chown -Rh $(stat -c "%u:%g" "$i") "$i"
done
您还可以使用
chown --reference=RFILE
从引用复制所有权数据,但这不会显示实际的 uid 和 gid 值。
for i in /home/*/
do
echo chown -Rh --reference="$i" "$i"
done
当您手动检查一切都正确后,删除
echo
以实际运行命令。
chown 命令采用用户和组的名称或 id(字符串或数字),即:
chown root:staff /some/file
or
chown 0:20 /some/file
只需在
ls -l
目录上运行 /home
即可显示每个主目录所有者的用户名和组名。如果你想要数字版本,你可以这样做 ls -ln
从那里开始,只需将输出重新格式化为一系列
chown
命令即可。您可以手动执行此操作或使用类似 sed
的内容,即:
sed -E 's/^.{15} *([^ ]*) *([^ ]*) *[0-9]*.{14}(.*)$/chown -R \1:\2 \3/g'
注意:我不会保证特定的正则表达式是完美的,我处理了一些边缘情况,但可能还有更多,因此您可能需要稍微调整正则表达式。
编辑:更新以合并为一行:
eval "$( ls -ln | sed -E '1d;s/^.{10} *[0-9]* *([^ ]*) *([^ ]*) *[0-9]*.{14}(.*)$/chown -R \1:\2 \3/g' )"
注意:请在运行整个过程之前测试其中的各个部分,因为您可能会遇到一些我没有考虑到的奇怪的极端情况。