SSD Nodes Learn Hosting plans →
指南 Matt Connor作者: Matt Connor · 更新于 2026-09-13

chown 命令到底修改了什么?Linux 文件所有权详解

chown 修改 Linux 文件的所有者和所属组,不是权限位。本文说明先创建账户、使用 chown user:group 与 chown -R,并修复 sudo 后产生的 root 所有文件。

Verified Every command ran end-to-end on a fresh Ubuntu 24.04 server, August 22, 2026.

chown 命令会修改什么

chown 命令用于设置文件的所有者用户和所属组。Linux 文件系统中的每个文件都恰好有一个所有者和一个所属组,作为两个数字记录在 inode 中。权限位本身无法决定访问结果:内核会先判断进程是文件所有者、文件所属组的成员,还是两者都不是,然后才读取相应的一组权限位。

因此,程序无法写入文件时,首先应检查所有权。如果文件属于其他账号,修改权限位也没有帮助。有关权限位本身的说明,请参阅 ls -l 列表中 drwxr-xr-x 的含义

在设置所有权之前创建账户

目录列表中的名称不会存储在磁盘上。内核存储的是 UID(用户标识符)和 GID(组标识符),ls 会在 /etc/passwd/etc/group 中查找这些编号,并显示对应的名称。因此,如果某个名称无法在本机解析,chown 就会拒绝该名称。先创建账户。

sudo adduser --disabled-password --gecos "" appuser
id appuser
uid=1001(appuser) gid=1001(appuser) groups=1001(appuser)

实际使用的编号会不同,因为 adduser 会分配下一个可用的 UID,并创建一个匹配的组。--disabled-password 会使该账户没有可用密码,适合用于拥有文件并运行服务、但从不登录的账户。--gecos "" 会跳过全名和电话号码提示,因此命令执行时不会询问这些信息。

如果账户完全不应有主目录,sudo adduser --system --group --no-create-home appsvc 是服务账户形式。两种情况下的所有权行为相同。每个账户只保留必要权限,这正是使用最小权限用户运行服务的目的。

Ubuntu 还自带可直接使用的账户,无需创建。www-data 是 nginx 和 Apache 用于降权运行工作进程的账户。

id www-data
uid=33(www-data) gid=33(www-data) groups=33(www-data)

使用 ls -ld 和 stat 读取当前所有者

ls -ld 对目录执行时,会报告目录本身,而不是列出其中的内容。

ls -ld /srv/inventory /srv/inventory/config.yml
drwxr-xr-x 3 root root 4096 Aug 22 15:42 /srv/inventory
-rw-r--r-- 1 root root  318 Aug 22 15:42 /srv/inventory/config.yml

stat 会将数字显示在名称旁边。

stat /srv/inventory/config.yml
  File: /srv/inventory/config.yml
  Size: 318            Blocks: 8          IO Block: 4096   regular file
Device: 254,1    Inode: 1443329     Links: 1
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2026-08-22 15:42:10.104728311 +0000
Modify: 2026-08-22 15:42:10.104728311 +0000
Change: 2026-08-22 15:42:10.104728311 +0000
 Birth: 2026-08-22 15:42:10.100728290 +0000

stat -c 只输出您指定的字段,脚本中应使用这种形式。

stat -c '%U %G %u %g %n' /srv/inventory/config.yml
root root 0 0 /srv/inventory/config.yml

chown 命令的写法

4 种写法分别执行不同的操作。

  • sudo chown appuser file 设置所有者,不修改所属组。
  • sudo chown appuser:appuser file 一次设置所有者和所属组。
  • sudo chown :www-data file 仅设置所属组,不修改所有者。
  • sudo chown appuser: file 设置所有者,并将所属组设置为该用户的登录组。

chgrp 单独表示所属组部分,因此 sudo chgrp www-data filesudo chown :www-data file 执行相同的操作。在笔记中选择更清晰的写法即可。

sudo chown appuser:www-data /srv/inventory/config.yml
ls -ld /srv/inventory/config.yml
-rw-r--r-- 1 appuser www-data 318 Aug 22 15:44 /srv/inventory/config.yml

为什么 chown 命令需要 sudo

更改所有者需要 CAP_CHOWN capability。在普通系统上,这通常意味着需要 root。即使您已经拥有某个文件,也不能将其所有权转让给其他人。

chown appuser notes.txt
chown: changing ownership of 'notes.txt': Operation not permitted

这是因为磁盘配额按所有者计算。如果用户可以将文件转给其他人,就能把无限量的数据存放到同事的配额中,还能植入一个看起来像是由该同事创建的文件。

组的限制较少。您可以在不使用 sudo 的情况下,将自己拥有的文件 chgrp 给您所属的任意组。指定您不属于的组会导致 chgrp: changing group of 'notes.txt': Operation not permitted

chown -R 以及两种常见错误用法

-R 会遍历目录,并将其中所有内容的所有权设置为相同值。

sudo chown -R appuser:appuser /srv/inventory

第一种风险是多了一个空格。sudo chown -R appuser / srv/inventory 是一条包含两个目标的有效命令,其中第一个目标是文件系统根目录。它会改写磁盘上每个文件的所有者,包括 /usr/bin/sudo,因此你下一次运行 sudo 时会看到:

sudo: /usr/bin/sudo must be owned by uid 0 and have the setuid bit set

此后无法再通过 SSH 切换为 root,恢复操作需要使用服务商提供的救援控制台。在执行递归 chown 前,务必仔细检查路径。

第二种风险不易察觉。-R 会抹平原本有意设置为不同所有者的目录树。如果只有部分目录树的所有权不正确,请使用 --from 限制修改范围。该选项仅在文件当前所有权匹配时修改文件。

sudo chown -R --from=root:root appuser:appuser /srv/inventory

--reference 会从一个所有权已经正确的文件复制所有权,因此无需查询任何名称。

sudo chown --reference=/srv/inventory/config.yml /srv/inventory/secrets.yml

符号链接有单独的处理规则。普通的 chown 会跟随链接并修改链接另一端的文件,而 -h 会修改链接本身。chown -R 不会通过符号链接进入其指向的目录,-L 则是启用该行为的选项。

案例 1:使用 sudo 复制后所有内容都归 root 所有

以 root 身份运行的进程会创建归 root 所有的文件。因此,sudo cpsudo tar -xsudo unzipsudo git clone 都会留下一个您无法写入的目录树,即使它位于您自己的主目录中。

sudo cp -r /srv/backup/inventory ~/inventory
ls -ld ~/inventory ~/inventory/config.yml
drwxr-xr-x 3 root root 4096 Aug 22 15:47 /home/deploy/inventory
-rw-r--r-- 1 root root  318 Aug 22 15:47 /home/deploy/inventory/config.yml

最初的症状通常是编辑器拒绝写入。这与 nano 因权限被拒绝而无法保存 的原因相同。Git 也有类似提示,因为它在运行前会检查仓库目录的所有者:

fatal: detected dubious ownership in repository at '/home/deploy/inventory'

添加 safe.directory 例外可以消除该提示,但您仍然无法写入。请改为修复所有权。

sudo chown -R "$USER:$(id -gn)" ~/inventory
ls -ld ~/inventory
drwxr-xr-x 3 deploy deploy 4096 Aug 22 15:47 /home/deploy/inventory

$USER$(id -gn) 会在 sudo 启动前由您自己的 shell 展开,因此其中保存的是您的用户名和登录组,而不是 root 的信息。在 Ubuntu 中,每个账户都会获得一个同名组,因此 "$USER:$USER" 通常也可以使用。$(id -gn) 在任何主机上都正确。

更好的做法是避免产生这个问题。目标目录已经归您所有时,不要使用 sudo 进行克隆和解压。要写入 /srv/opt,才需要 sudo;写入您的主目录不需要它。

案例 2:服务或容器无法写入其数据目录

Nginx 和 Apache 以 www-data 身份运行,因此该账户必须能够写入上传目录或缓存目录。直接确认实际使用的账户,不要猜测。

sudo -u www-data touch /srv/inventory/uploads/.probe
touch: cannot touch '/srv/inventory/uploads/.probe': Permission denied

创建文件实际上是写入目录,因此需要检查目录的所有权,而不是目录中现有文件的所有权。将数据目录交给该账户,然后再次测试。

sudo chown -R www-data:www-data /srv/inventory/uploads
sudo -u www-data touch /srv/inventory/uploads/.probe
ls -ld /srv/inventory/uploads
drwxr-xr-x 2 www-data www-data 4096 Aug 22 15:50 /srv/inventory/uploads

不输出任何内容的 touch 表示 touch 执行成功。只将数据目录授予服务账户。应用代码和配置仍可归部署账户所有,这样工作进程被入侵后就无法改写正在运行的代码。

容器还存在一个特殊情况。容器拥有自己的 /etc/passwd,因此镜像内名为 nodeabc 的用户,在主机上没有任何意义。通过 bind mount 传递的是数字。

docker run --rm --user 1000:1000 -v /srv/inventory/data:/data alpine:3.21 touch /data/probe
touch: /data/probe: Permission denied

主机目录归 root 所有,而容器内的 UID 1000 在主机上同样是 UID 1000。将主机目录的所有权设置为容器进程使用的数字。

sudo chown -R 1000:1000 /srv/inventory/data
stat -c '%u:%g %U:%G %n' /srv/inventory/data
1000:1000 deploy:deploy /srv/inventory/data

chown 接受纯数字,即使没有账户拥有该数字。这就是出现此类目录列表的原因。

sudo chown -R 5000:5000 /srv/inventory/data
ls -ld /srv/inventory/data
drwxr-xr-x 2 5000 5000 4096 Aug 22 15:52 /srv/inventory/data

这里没有任何问题。/etc/passwd 没有将 5000 映射到名称的条目,因此没有名称可供显示。许多容器镜像会在启动时根据两个环境变量完成此所有权设置,这正是容器镜像中的 PUID 和 PGID 变量的用途。

错误及其含义

  • chown: invalid user: 'appuser' 表示该名称无法在此主机上解析。使用 id appuser 检查。容器内创建的账户在运行该容器的主机上不存在。
  • chgrp: invalid group: 'appgroup' 表示组方面出现相同错误。组不存在时,getent group appgroup 不会输出任何内容。
  • chown: cannot access '/srv/inventry': No such file or directory 表示路径拼写错误。chown 不会创建任何内容。
  • 以 root 身份运行时,chown: changing ownership of 'x': Operation not permitted 指向的是文件系统,而不是当前用户。vfat、exfat 以及大多数 SMB 或 CIFS 挂载不会在磁盘上保存 Unix 所有权。它们会在挂载时使用固定的 uid=gid=,因此无法对其执行 chown。请改为在 /etc/fstab 中修改挂载选项。
  • chown: changing ownership of 'x': Read-only file system 表示挂载点为只读。请先将其重新挂载为读写模式。

所有权说明文件属于谁。权限位说明可以对文件执行哪些操作,并且需要使用不同的命令设置:请参阅 chmod 数字模式和符号模式

FAQ

chown 在我已经拥有文件的情况下为什么仍提示 “Operation not permitted”?

拥有文件并不意味着可以转让文件所有权。更改所有者需要 CAP_CHOWN capability。在普通 Linux 系统中,这通常意味着以 root 身份运行,因此 sudo chown ... 是解决方法。如果命令已经通过 sudo 运行但仍然失败,请检查文件系统。vfat、exfat 以及大多数 SMB 或 CIFS 挂载不会存储 Unix 所有权,而是从挂载选项中采用固定的 uid=gid=,因此 chown 无法在那里更改任何内容。

chown 和 chgrp 有什么区别?

chgrp appgroup file 只更改组,不更改其他内容。chown 使用 chown :appgroup file 完成相同的操作,同时还可以更改所有者,而 chgrp 不能更改所有者。一个实际区别是:只要您属于目标组,就可以在自己拥有的文件上运行 chgrp,而无需 sudo。

ls -l 为什么显示数字而不是用户名?

因为本机的 /etc/passwd 中没有将该 UID 映射到名称的条目。文件本身没有问题,其所有权正是显示的内容。从其他主机复制文件、恢复备份,或使用 chown 1000:1000 为容器用户设置所有权后,出现这种情况很正常。运行 getent passwd 1000 检查账户是否存在;如果输出为空,则表示该账户不存在。

chown -R 是否会跟随符号链接?

默认不会。chown -R 不会沿着符号链接进入其指向的目录,-L 是启用此行为的标志。不使用 -R 时,对符号链接执行普通的 chown 会更改链接指向的文件;使用 -h 则会更改符号链接本身。

如何撤销误作用于错误目录的 chown -R?

无法撤销,因为 chown 不会记录之前的所有权。在执行任何批量更改前,请自行保存记录:find /srv/inventory -printf '%U:%G %p\n' > ~/owners.txt 为每个文件写入一行,短脚本即可根据记录重放更改。对于来自软件包的文件,sudo apt install --reinstall <package> 可以恢复该软件包发布时使用的所有权。对于其他文件,只能从备份恢复。

#chown#permissions#ownership#linux#ubuntu