chown 命令详解与参数实测(Ubuntu 22.04)

GNU chown 参数实测:owner:group 与点号语法、数字 UID/GID、-c/-v/-f、-h 软链解引用、-R 与 -H/-L/-P 遍历语义、--from 条件变更、--reference 及 invalid user/Operation not permitted 错误形态,Ubuntu 22.04 实测。

Linux命令Linux系统UbuntuUbuntu 22.04命令行用户权限2026/10/15

chown 命令详解与参数实测(Ubuntu 22.04)

目标:全面掌握 chown 的每一个常用参数——修改属主、owner:group 同时修改、只改属组、数字 UID/GID、-c/-v/-f 输出控制、-h 软链本身与默认解引用、-R 递归及 -H/-L/-P 三种遍历语义、--from 条件变更、--reference 参照文件,以及 invalid user、Operation not permitted 等错误形态,全部命令与回显已在 Ubuntu 22.04(GNU coreutils 8.32)实测通过。

一、环境信息

本篇所有命令与回显均来自同一台 Ubuntu 22.04 服务器的实测,演示数据统一放在 /root/demo/chown/ 下,另在 /tmp/u4d-demo/ 做普通用户权限实验。读者在任意 Ubuntu 22.04 机器上按相同步骤均可复现。

  • 操作系统:Ubuntu 22.04.5 LTS(x86_64)
  • chown 版本:GNU coreutils 8.32(chown --version 实测)
  • chown 属于 coreutils 基础工具集,Ubuntu 22.04 默认预装,无需额外安装
  • 演示目录:/root/demo/chown/(root 身份操作);/tmp/u4d-demo/(普通用户实验)
  • 测试用户与组:u4d1(uid=1000,主组 u4d1)、u4d2(uid=1001,主组 u4d2,附加组 u4dgrp1/u4dgrp2)、u4dgrp1(gid=1001)、u4dgrp2(gid=1002)
  • 准备命令(已存在的用户/组会报 File exists,忽略即可):
useradd -m u4d1 && useradd -m u4d2
groupadd u4dgrp1 && groupadd u4dgrp2
usermod -aG u4dgrp1,u4dgrp2 u4d2

二、命令概览

2.1 语法与测试数据

chown 的语法共两种形态(摘自帮助 Usage 行):chown [OPTION]... [OWNER][:[GROUP]] FILE... 按名字/数字修改属主属组,chown [OPTION]... --reference=RFILE FILE... 参照另一个文件对齐属主属组。属主部分(OWNER)与属组部分(GROUP)都可以省略,省略即"不修改"。

准备演示数据——两个普通文件、一棵带子目录与树内软链的目录树、两个软链(一个指向文件、一个指向目录):

mkdir -p /root/demo/chown/tree/sub1 /root/demo/chown/tree/sub2
echo 'chown demo a' > /root/demo/chown/a.txt
echo 'chown demo b' > /root/demo/chown/b.txt
echo 'ref content'  > /root/demo/chown/ref.txt
echo inner1 > /root/demo/chown/tree/sub1/inner1.txt
echo inner2 > /root/demo/chown/tree/sub2/inner2.txt
ln -s ../sub2/inner2.txt /root/demo/chown/tree/sub1/link_inner2
ln -s /root/demo/chown/a.txt /root/demo/chown/link_a
ln -s /root/demo/chown/tree /root/demo/chown/link_tree

验证数据就绪:

$ ls -l /root/demo/chown
total 16
-rw-r--r-- 1 root root   13 Oct 15 08:43 a.txt
-rw-r--r-- 1 root root   13 Oct 15 08:43 b.txt
lrwxrwxrwx 1 root root   22 Oct 15 08:43 link_a -> /root/demo/chown/a.txt
lrwxrwxrwx 1 root root   21 Oct 15 08:43 link_tree -> /root/demo/chown/tree
-rw-r--r-- 1 root root   12 Oct 15 08:43 ref.txt
drwxr-xr-x 4 root root 4096 Oct 15 08:43 tree
$ ls -lR /root/demo/chown/tree
/root/demo/chown/tree:
total 8
drwxr-xr-x 2 root root 4096 Oct 15 08:43 sub1
drwxr-xr-x 2 root root 4096 Oct 15 08:43 sub2

/root/demo/chown/tree/sub1:
total 4
-rw-r--r-- 1 root root  7 Oct 15 08:43 inner1.txt
lrwxrwxrwx 1 root root 18 Oct 15 08:43 link_inner2 -> ../sub2/inner2.txt

/root/demo/chown/tree/sub2:
total 4
-rw-r--r-- 1 root root 7 Oct 15 08:43 inner2.txt

确认测试用户的 uid/gid,后文所有属主变化都围绕它们观察:

$ id u4d1
uid=1000(u4d1) gid=1000(u4d1) groups=1000(u4d1)

$ id u4d2
uid=1001(u4d2) gid=1003(u4d2) groups=1003(u4d2),1001(u4dgrp1),1002(u4dgrp2)

2.2 --help 全量输出

chown --help 输出全部参数清单(实测原样保留,可作为参数速查):

Usage: chown [OPTION]... [OWNER][:[GROUP]] FILE...
  or:  chown [OPTION]... --reference=RFILE FILE...
Change the owner and/or group of each FILE to OWNER and/or GROUP.
With --reference, change the owner and group of each FILE to those of RFILE.

  -c, --changes          like verbose but report only when a change is made
  -f, --silent, --quiet  suppress most error messages
  -v, --verbose          output a diagnostic for every file processed
      --dereference      affect the referent of each symbolic link (this is
                         the default), rather than the symbolic link itself
  -h, --no-dereference   affect symbolic links instead of any referenced file
                         (useful only on systems that can change the
                         ownership of a symlink)
      --from=CURRENT_OWNER:CURRENT_GROUP
                         change the owner and/or group of each file only if
                         its current owner and/or group match those specified
                         here.  Either may be omitted, in which case a match
                         is not required for the omitted attribute
      --no-preserve-root  do not treat '/' specially (the default)
      --preserve-root    fail to operate recursively on '/'
      --reference=RFILE  use RFILE's owner and group rather than
                         specifying OWNER:GROUP values
  -R, --recursive        operate on files and directories recursively

The following options modify how a hierarchy is traversed when the -R
option is also specified.  If more than one is specified, only the final
one takes effect.

  -H                     if a command line argument is a symbolic link
                         to a directory, traverse it
  -L                     traverse every symbolic link to a directory
                         encountered
  -P                     do not traverse any symbolic links (default)

      --help     display this help and exit
      --version  output version information and exit

Owner is unchanged if missing.  Group is unchanged if missing, but changed
to login group if implied by a ':' following a symbolic OWNER.
OWNER and GROUP may be numeric as well as symbolic.

Examples:
  chown root /u        Change the owner of /u to "root".
  chown root:staff /u  Likewise, but also change its group to "staff".
  chown -hR root /u    Change the owner of /u and subfiles to "root".

GNU coreutils online help: <https://www.gnu.org/software/coreutils/>
Report any translation bugs to <https://translationproject.org/team/>
Full documentation <https://www.gnu.org/software/coreutils/chown>
or available locally via: info '(coreutils) chown invocation'

💡 说明:帮助末尾两段最关键——"Owner is unchanged if missing"(省略属主就不改属主)、"changed to login group if implied by a ':' following a symbolic OWNER"(owner: 冒号结尾会把属组重置为该属主的登录组)。-H/-L/-P 只在配合 -R 时生效,多个同时给出时只有最后一个生效。

2.3 版本确认

$ chown --version | head -1
chown (GNU coreutils) 8.32

三、参数逐项实测

3.1 基本用法:只改属主

命令格式为 chown OWNER FILE。只给属主不给属组时,属组保持不变——这是帮助文本 "Owner is unchanged if missing" 的直接体现。先把 a.txt 的属主改为 u4d1,再改为 u4d2,ls -l 第三、四列分别为属主与属组:

$ chown u4d1 /root/demo/chown/a.txt

$ ls -l /root/demo/chown/a.txt
-rw-r--r-- 1 u4d1 root 13 Oct 15 08:43 /root/demo/chown/a.txt

$ chown u4d2 /root/demo/chown/b.txt

$ ls -l /root/demo/chown/b.txt
-rw-r--r-- 1 u4d2 root 13 Oct 15 08:43 /root/demo/chown/b.txt

💡 要点:改属主时属组纹丝不动(两次实测都是 root)。修改属主需要内核能力 CAP_CHOWN,普通用户连自己的文件都不能把属主让给别人(3.14 有实测)。

3.2 owner:group 同时修改属主与属组

冒号分隔属主与属组,一次调用同时改两个属性:

$ chown u4d2:u4dgrp1 /root/demo/chown/a.txt

$ ls -l /root/demo/chown/a.txt
-rw-r--r-- 1 u4d2 u4dgrp1 13 Oct 15 08:43 /root/demo/chown/a.txt

属主、属组一列三态:u4d2(只改属主)、u4d2:u4dgrp1(都改)、:u4dgrp1(只改属组,见 3.4)。

另一个实测点是"冒号结尾":chown u4d1: FILE 中冒号后组名为空,按帮助文本的规则,属组会被重置为属主 u4d1 的登录组(u4d1 用户的主组恰好也叫 u4d1)。实测 a.txt 原属组是 u4dgrp1:

$ chown u4d1: /root/demo/chown/a.txt

$ ls -l /root/demo/chown/a.txt
-rw-r--r-- 1 u4d1 u4d1 13 Oct 15 08:43 /root/demo/chown/a.txt

💡 要点:owner: 与 owner 不同——前者把属组重置为属主的登录组,后者完全不碰属组。清理"属主换了、组还挂在别人头上"的残留时,chown user: 一条顶两条。

3.3 老式点号语法 owner.group

chown 兼容 BSD 时代的点号分隔符 owner.group,行为与冒号完全一致:

$ chown u4d2.u4dgrp2 /root/demo/chown/b.txt

$ ls -l /root/demo/chown/b.txt
-rw-r--r-- 1 u4d2 u4dgrp2 13 Oct 15 08:43 /root/demo/chown/b.txt

点号同样支持 .group 只改属组:

$ chown .u4dgrp2 /root/demo/chown/b.txt

$ ls -l /root/demo/chown/b.txt
-rw-r--r-- 1 u4d2 u4dgrp2 13 Oct 15 08:43 /root/demo/chown/b.txt

💡 要点:点号是历史遗留语法。现代系统允许用户名本身含点号(如 john.doe),此时 chown john.doe FILE 会被解析成属主 john、属组 doe 而不是属主 john.doe,脚本里应统一用冒号,避免歧义。

3.4 :group 只改属组不改属主

属主位置留空、冒号紧跟组名,即可只改属组。a.txt 当前属主是 u4d2,改完仍是 u4d2:

$ chown :u4dgrp1 /root/demo/chown/a.txt

$ ls -l /root/demo/chown/a.txt
-rw-r--r-- 1 u4d2 u4dgrp1 13 Oct 15 08:43 /root/demo/chown/a.txt

💡 要点::group 与 chgrp 等价(chgrp 篇有专门实测)。区别在于 chown 还允许普通用户在"目标组是自己所属组"时改组,而改属主永远只有 root 能做。要复用既有文件的属组又不想多敲一条命令时,chown --reference(3.13)更省事。

3.5 数字 UID/GID

OWNER 与 GROUP 都可以直接写数字(帮助原文 "OWNER and GROUP may be numeric as well as symbolic")。数字形式绕过名称解析:系统里不存在对应名称也照改不误。用 ls -ln(以数字显示属主属组)验证:

$ chown 1001:1002 /root/demo/chown/a.txt

$ ls -ln /root/demo/chown/a.txt
-rw-r--r-- 1 1001 1002 13 Oct 15 08:43 /root/demo/chown/a.txt

$ chown 65534 /root/demo/chown/b.txt

$ ls -ln /root/demo/chown/b.txt
-rw-r--r-- 1 65534 1002 13 Oct 15 08:43 /root/demo/chown/b.txt

$ ls -l /root/demo/chown/b.txt
-rw-r--r-- 1 nobody u4dgrp2 13 Oct 15 08:43 /root/demo/chown/b.txt

💡 要点:ls -l 与 ls -ln 对照可以看出 65534 就是 nobody。数字形式在以下场景不可替代:批量迁移数据前目标用户还没建(先按数字把属主设好)、UID 在两台机器间不一致需要人工指定、name resolution 故障时的兜底。注意 chown 100 FILE 会把属主设为 uid=100 而不是名为"100"的用户——想用名为纯数字的用户名只能写 chown 100: FILE 加冒号消除歧义(coreutils 官方文档的建议做法)。

3.6 -c/--changes:只输出发生变化的条目

-c 只在属性真的变化时打印一行。a.txt 属主已是 u4d1 时再执行 chown -c u4d1,零输出;先把属主改成 u4d2 再改回 u4d1,changed 行立刻出现:

$ chown -c u4d1 /root/demo/chown/a.txt

$ chown -c u4d1 /root/demo/chown/a.txt

$ chown u4d2 /root/demo/chown/a.txt

$ chown -c u4d1 /root/demo/chown/a.txt
changed ownership of '/root/demo/chown/a.txt' from u4d2 to u4d1

$ chown -c u4d1 /root/demo/chown/a.txt

💡 要点:-c 的价值在脚本里——批量修改几千个文件时,只打印真正动过的条目,输出干净且可直接进日志审计。"无变化零输出、有变化一行"也常被用作 shell 判断依据。

3.7 -v/--verbose:无论是否变化都输出

-v 对每个处理的文件都打印诊断行,变化了输出 changed,没变化输出 retained:

$ chown -v u4d2 /root/demo/chown/a.txt
changed ownership of '/root/demo/chown/a.txt' from u4d1 to u4d2

$ chown -v u4d2 /root/demo/chown/a.txt
ownership of '/root/demo/chown/a.txt' retained as u4d2

💡 要点:retained(保持)与 changed(变化)两种措辞对应"属性相同"与"属性不同"两种结果。配合 -R 时 -v 会逐文件刷屏,排查"到底改了哪些路径"时非常有用。

3.8 -f/--silent:抑制运行期错误消息

-f 抑制大多数错误消息。但它抑制的是"运行期失败"(如权限不够),对"参数解析失败"(用户/组不存在)无效——invalid user 依旧照报:

$ chown -f nosuchuser /root/demo/chown/a.txt
chown: invalid user: 'nosuchuser'

而普通用户改属主的 Operation not permitted 属于运行期错误,-f 可以完全静默(实测见 3.14)。

💡 要点:-f 典型用途是批量 chown -R -f 时忽略个别无权限路径的报错噪音,让脚本输出只关心最终结果。但也要小心:静默后失败只有退出码非零可判,脚本里建议同时检查 $?。

3.9 -h/--no-dereference:改软链本身;默认解引用改目标

link_a 是指向 a.txt 的软链。不加 -h 时 chown 默认解引用(--dereference),改的是 a.txt;软链本身的属主纹丝不动:

$ chown u4d2 /root/demo/chown/link_a

$ ls -l /root/demo/chown/link_a /root/demo/chown/a.txt
-rw-r--r-- 1 u4d2 u4dgrp1 13 Oct 15 08:43 /root/demo/chown/a.txt
lrwxrwxrwx 1 root root    22 Oct 15 08:43 /root/demo/chown/link_a -> /root/demo/chown/a.txt

加 -h 后作用于软链本身,a.txt 反而没动:

$ chown -h u4d1 /root/demo/chown/link_a

$ ls -l /root/demo/chown/link_a /root/demo/chown/a.txt
-rw-r--r-- 1 u4d2 u4dgrp1 13 Oct 15 08:43 /root/demo/chown/a.txt
lrwxrwxrwx 1 u4d1 root    22 Oct 15 08:43 /root/demo/chown/link_a -> /root/demo/chown/a.txt

💡 要点:软链属主在 Linux 上对"谁能改这个链接本身"有意义(受父目录写权限约束),对访问目标文件不起作用,但备份/同步工具(rsync -a、tar)会保留它,属主错乱会让恢复出来的文件权限校验失败。帮助文本也注明 -h 只在"系统能改软链属主"的内核上有意义,Linux 从 2.1.126 起支持。

3.10 -R/--recursive:递归修改整棵目录树

-R 对目录逐层下钻,把目录、子目录、目录内所有文件(含树内软链本身)一并修改。先复位为 root,再一次性交给 u4d1:u4dgrp1:

$ chown -R root:root /root/demo/chown/tree

$ chown -R u4d1:u4dgrp1 /root/demo/chown/tree

$ ls -lR /root/demo/chown/tree
/root/demo/chown/tree:
total 8
drwxr-xr-x 2 u4d1 u4dgrp1 4096 Oct 15 08:43 sub1
drwxr-xr-x 2 u4d1 u4dgrp1 4096 Oct 15 08:43 sub2

/root/demo/chown/tree/sub1:
total 4
-rw-r--r-- 1 u4d1 u4dgrp1  7 Oct 15 08:43 inner1.txt
lrwxrwxrwx 1 u4d1 u4dgrp1 18 Oct 15 08:43 link_inner2 -> ../sub2/inner2.txt

/root/demo/chown/tree/sub2:
total 4
-rw-r--r-- 1 u4d1 u4dgrp1 7 Oct 15 08:43 inner2.txt

💡 要点:注意 link_inner2 这条软链——ls -l 显示它自身属主也变成了 u4d1 u4dgrp1,说明 -R 遍历时对"不跟随"的树内软链,是把软链本身当文件对象改的(跟随与否由 -H/-L/-P 决定,见 3.11)。实战中 /home 迁移用户、/var/www 交给运行账户,都是 -R 的高频场景。

3.11 -H/-L/-P 与 -R 的组合遍历语义

帮助文本明确:这三个选项只在 -R 下有意义,同时给出时只有最后一个生效。语义对照:

选项遍历语义对命令行参数中的软链对遍历途中遇到的软链
-P(默认)不跟随任何软链只改软链本身只改软链本身
-H仅命令行参数解引用跟随并进入其指向的目录树不跟随,只改软链本身
-L全部解引用跟随跟随,指向目录就下钻

准备状态:link_tree 是指向 tree 的命令行软链,tree 内部还有一条 link_inner2 软链。三个实验之间都用 chown -R root:root 复位。

实验一,默认(等价 -P):只改了 link_tree 软链本身,tree 内部纹丝不动:

$ chown -R root:root /root/demo/chown/tree /root/demo/chown/link_tree /root/demo/chown/a.txt

$ chown -R u4d2:u4dgrp2 /root/demo/chown/link_tree

$ ls -l /root/demo/chown/link_tree
lrwxrwxrwx 1 u4d2 u4dgrp2 21 Oct 15 08:43 /root/demo/chown/link_tree -> /root/demo/chown/tree

$ ls -lR /root/demo/chown/tree
/root/demo/chown/tree:
total 8
drwxr-xr-x 2 root root 4096 Oct 15 08:43 sub1
drwxr-xr-x 2 root root 4096 Oct 15 08:43 sub2

/root/demo/chown/tree/sub1:
total 4
-rw-r--r-- 1 root root  7 Oct 15 08:43 inner1.txt
lrwxrwxrwx 1 root root 18 Oct 15 08:43 link_inner2 -> ../sub2/inner2.txt

/root/demo/chown/tree/sub2:
total 4
-rw-r--r-- 1 root root 7 Oct 15 08:43 inner2.txt

实验二,-H:命令行上的 link_tree 被解引用,整棵 tree 被改;但树内的 link_inner2 没有被跟随——它本身保持 root,而它指向的 inner2.txt 是通过目录遍历改到的:

$ chown -R root:root /root/demo/chown/tree /root/demo/chown/link_tree

$ chown -R -H u4d1:u4dgrp1 /root/demo/chown/link_tree

$ ls -lR /root/demo/chown/tree
/root/demo/chown/tree:
total 8
drwxr-xr-x 2 u4d1 u4dgrp1 4096 Oct 15 08:43 sub1
drwxr-xr-x 2 u4d1 u4dgrp1 4096 Oct 15 08:43 sub2

/root/demo/chown/tree/sub1:
total 4
-rw-r--r-- 1 u4d1 u4dgrp1  7 Oct 15 08:43 inner1.txt
lrwxrwxrwx 1 root root    18 Oct 15 08:43 link_inner2 -> ../sub2/inner2.txt

/root/demo/chown/tree/sub2:
total 4
-rw-r--r-- 1 u4d1 u4dgrp1 7 Oct 15 08:43 inner2.txt

$ ls -l /root/demo/chown/tree/sub1/link_inner2
lrwxrwxrwx 1 root root 18 Oct 15 08:43 /root/demo/chown/tree/sub1/link_inner2 -> ../sub2/inner2.txt

$ ls -l /root/demo/chown/tree/sub2/inner2.txt
-rw-r--r-- 1 u4d1 u4dgrp1 7 Oct 15 08:43 /root/demo/chown/tree/sub2/inner2.txt

实验三,-L:所有软链全部解引用。link_inner2 指向 ../sub2/inner2.txt(文件而非目录),跟随的结果是 inner2.txt 被直接改到;目录、文件全部变成 u4d2:u4dgrp2,而 link_inner2 软链本身的属主不再被碰(保持 root):

$ chown -R root:root /root/demo/chown/tree /root/demo/chown/link_tree /root/demo/chown/a.txt

$ chown -R -L u4d2:u4dgrp2 /root/demo/chown/link_tree

$ ls -lR /root/demo/chown/tree
/root/demo/chown/tree:
total 8
drwxr-xr-x 2 u4d2 u4dgrp2 4096 Oct 15 08:43 sub1
drwxr-xr-x 2 u4d2 u4dgrp2 4096 Oct 15 08:43 sub2

/root/demo/chown/tree/sub1:
total 4
-rw-r--r-- 1 u4d2 u4dgrp2  7 Oct 15 08:43 inner1.txt
lrwxrwxrwx 1 root root    18 Oct 15 08:43 link_inner2 -> ../sub2/inner2.txt

/root/demo/chown/tree/sub2:
total 4
-rw-r--r-- 1 u4d2 u4dgrp2 7 Oct 15 08:43 inner2.txt

$ ls -l /root/demo/chown/a.txt
-rw-r--r-- 1 root root 13 Oct 15 08:43 /root/demo/chown/a.txt

-P 显式指定时与默认完全一致:

$ chown -R root:root /root/demo/chown/tree /root/demo/chown/link_tree

$ chown -R -P u4d1:u4dgrp1 /root/demo/chown/link_tree

$ ls -l /root/demo/chown/link_tree
lrwxrwxrwx 1 u4d1 u4dgrp1 21 Oct 15 08:43 /root/demo/chown/link_tree -> /root/demo/chown/tree

$ ls -l /root/demo/chown/tree
total 8
drwxr-xr-x 2 root root 4096 Oct 15 08:43 sub1
drwxr-xr-x 2 root root 4096 Oct 15 08:43 sub2

💡 要点:三个实验的差异一目了然——默认/-P 最保守(软链是"墙",改墙不穿墙);-H 只穿透命令行指名的软链,适合"给一个软链路径但想改真实目录"的场景;-L 见链就穿,威力最大也最危险(软链指向上级目录会造成无限循环,GNU 实现靠遍历深度与 inode 记忆规避,但树外文件可能被误改,实测 -L 时 link_inner2 指向的 inner2.txt 被改到即是例证)。运维惯例:拿不准就用默认 -P,需要穿透时优先 -H。

3.12 --from:条件变更,当前属主匹配才修改

--from=当前属主[:当前属组] 给修改加前置条件,只有现状匹配才动手。先把 a.txt 设为 u4d2,然后只把"属主是 u4d2"的文件改为 u4d1;第二条命令条件不匹配(当前属主是 u4d1 不是 root),零输出零改动:

$ chown -c --from=u4d2 u4d1 /root/demo/chown/a.txt
changed ownership of '/root/demo/chown/a.txt' from u4d2 to u4d1

$ chown -c --from=root u4d1 /root/demo/chown/a.txt

$ ls -l /root/demo/chown/a.txt
-rw-r--r-- 1 u4d1 u4dgrp1 13 Oct 15 08:43 /root/demo/chown/a.txt

属主与属组可以同时匹配(--from=owner:group),目标端也支持 owner:group:

$ chown -c --from=u4d1:u4dgrp1 u4d2:u4dgrp2 /root/demo/chown/a.txt
changed ownership of '/root/demo/chown/a.txt' from u4d1:u4dgrp1 to u4d2:u4dgrp2

$ chown -c --from=u4d2:u4dgrp2 root /root/demo/chown/a.txt
changed ownership of '/root/demo/chown/a.txt' from u4d2 to root

$ ls -l /root/demo/chown/a.txt
-rw-r--r-- 1 root u4dgrp2 13 Oct 15 08:43 /root/demo/chown/a.txt

💡 要点:--from 是批量修复时的"安全网"——例如误把整个数据目录 chown 成了 nobody 后,用 chown -R --from=nobody webapp:webapp /srv/data 只修正真正属于 nobody 的文件,不会误伤目录里本来就有主的其他文件。配合 -c 使用,改动清单一目了然。

3.13 --reference:参照另一个文件对齐属主属组

--reference=RFILE 不写 owner:group,直接把目标文件的属主与属组改成 RFILE 的现状。先把 ref.txt 设为 u4d2:u4dgrp2 作参照,再把 b.txt 对齐过去:

$ chown u4d2:u4dgrp2 /root/demo/chown/ref.txt

$ ls -l /root/demo/chown/ref.txt
-rw-r--r-- 1 u4d2 u4dgrp2 12 Oct 15 08:43 /root/demo/chown/ref.txt

$ chown u4d1:u4dgrp1 /root/demo/chown/b.txt

$ ls -l /root/demo/chown/b.txt
-rw-r--r-- 1 u4d1 u4dgrp1 13 Oct 15 08:43 /root/demo/chown/b.txt

$ chown --reference=/root/demo/chown/ref.txt /root/demo/chown/b.txt

$ ls -l /root/demo/chown/b.txt
-rw-r--r-- 1 u4d2 u4dgrp2 13 Oct 15 08:43 /root/demo/chown/b.txt

💡 要点:--reference 一次对齐两个属性,且天然规避名称拼写错误。典型场景:修完 /etc/passwd 或搬家后,"让这批文件的属主跟这个样本文件一模一样";配合 find ... -exec chown --reference=样本 {} + 可以按目录批量对齐。chgrp 也有同款参数(chgrp 篇实测)。

3.14 错误形态:invalid user / Operation not permitted

第一类错误:用户或组不存在。invalid user / invalid group 在参数解析阶段就失败,即使加 -f 也照样报(3.8 已实测):

$ chown nosuchuser /root/demo/chown/a.txt
chown: invalid user: 'nosuchuser'

$ chown u4d1:nosuchgrp /root/demo/chown/a.txt
chown: invalid group: 'u4d1:nosuchgrp'

第二类错误:普通用户改属主。虽然操作的是 u4d1 自己的文件,内核依然拒绝——改属主是 root(CAP_CHOWN)专属能力。先用 root 把 /tmp/u4d-demo/own.txt 设为 u4d1:u4dgrp1,再以 u4d1 身份尝试让给 u4d2:

$ chown u4d1:u4dgrp1 /tmp/u4d-demo/own.txt

$ ls -ld /tmp/u4d-demo
drwxr-xr-x 2 root root 4096 Oct 15 08:46 /tmp/u4d-demo

$ su u4d1 -c 'chown u4d2 /tmp/u4d-demo/own.txt'
chown: changing ownership of '/tmp/u4d-demo/own.txt': Operation not permitted

$ ls -l /tmp/u4d-demo/own.txt
-rw-r--r-- 1 u4d1 u4dgrp1 5 Oct 15 08:46 /tmp/u4d-demo/own.txt

加 -f 后这条运行期错误被完全静默(属主没变,但输出干净):

$ su u4d1 -c 'chown -f u4d2 /tmp/u4d-demo/own.txt'

$ ls -l /tmp/u4d-demo/own.txt
-rw-r--r-- 1 u4d1 u4dgrp1 5 Oct 15 08:46 /tmp/u4d-demo/own.txt

💡 要点:两条铁律——(1) 改属主只有 root 能做,普通用户即使是对自己 100% 拥有的文件也不行;(2) -f 只吞运行期错误(Operation not permitted),不吞参数错误(invalid user)。另外注意:如果以普通用户去操作一个因父目录权限而不可达的路径,报错会是 cannot access ... Permission denied(本文初测时在 /root 下就撞到过),路径可达性与属主变更失败是两类不同的报错。

3.15 chown 0:0 收回 root

数字形式 0:0 就是 root:root。收回权限是版本库/部署目录清理的最后一步:

$ chown -c 0:0 /root/demo/chown/a.txt
changed ownership of '/root/demo/chown/a.txt' from root:u4dgrp2 to 0:0

$ ls -l /root/demo/chown/a.txt
-rw-r--r-- 1 root root 13 Oct 15 08:43 /root/demo/chown/a.txt

💡 要点:注意 -c 输出里"from root:u4dgrp2 to 0:0"——数字与名字混排是常态,输出按输入形式回显。--no-preserve-root/--preserve-root 一对参数控制对 / 的保护:默认 chown -R user / 会被拒绝(preserve-root 是现代发行版的默认行为),显式 --no-preserve-root 才会放行,生产环境永远不要碰后者。

3.16 技术拓展:改属主/属组的三种命令

Linux 上"改文件归属"不止 chown 一条路。主要选项对比——

命令能改属主能改属组典型场景
chown✅(root 专属)✅一条命令同时改属主+属组,最常用
chgrp❌✅只关心属组的批量调整(如移交 www-data 组)
usermod -g/-G❌❌(改的是用户本身)调整用户的主组/附加组,间接影响新建文件的属组

💡 技术拓展:usermod 改的是"用户在 /etc/passwd、/etc/group 里的组身份",不动任何既有文件的属组;chown/chgrp 改的是"文件 inode 上的属主属组字段",不动用户身份。两者方向相反、互不替代:想让用户"以后新建文件归新组"用 usermod -g,想把"存量文件归到新组"用 chown/chgrp -R。本文实际采用 chown,因为它一条命令覆盖属主与属组两个维度,配合 -R/--from/--reference 覆盖了绝大多数归属修复场景。

四、实战示例

4.1 把网站目录整体交给运行账户

$ chown -R root:root /root/demo/chown/tree
$ chown -R u4d1:u4dgrp1 /root/demo/chown/tree
$ ls -lR /root/demo/chown/tree
/root/demo/chown/tree:
total 8
drwxr-xr-x 2 u4d1 u4dgrp1 4096 Oct 15 08:43 sub1
drwxr-xr-x 2 u4d1 u4dgrp1 4096 Oct 15 08:43 sub2

/root/demo/chown/tree/sub1:
total 4
-rw-r--r-- 1 u4d1 u4dgrp1  7 Oct 15 08:43 inner1.txt
lrwxrwxrwx 1 u4d1 u4dgrp1 18 Oct 15 08:43 link_inner2 -> ../sub2/inner2.txt

/root/demo/chown/tree/sub2:
total 4
-rw-r--r-- 1 u4d1 u4dgrp1 7 Oct 15 08:43 inner2.txt

💡 说明:-R 一次到位;目录、文件、树内软链本身全部换主。生产上把 /var/www 交给 www-data:www-data 同理。

4.2 用 --from 只修复误改的文件,不碰本来就有主的

$ chown -c --from=u4d2 u4d1 /root/demo/chown/a.txt
changed ownership of '/root/demo/chown/a.txt' from u4d2 to u4d1

💡 说明:目录里混着多批来源不同的文件时,--from 保证只动目标文件,其余原样保留——比先 chown -R root 再逐个改的做法安全得多。

4.3 软链与真实目录分开处理

$ chown -R -H u4d1:u4dgrp1 /root/demo/chown/link_tree
$ ls -lR /root/demo/chown/tree
/root/demo/chown/tree:
total 8
drwxr-xr-x 2 u4d1 u4dgrp1 4096 Oct 15 08:43 sub1
drwxr-xr-x 2 u4d1 u4dgrp1 4096 Oct 15 08:43 sub2

/root/demo/chown/tree/sub1:
total 4
-rw-r--r-- 1 u4d1 u4dgrp1  7 Oct 15 08:43 inner1.txt
lrwxrwxrwx 1 root root    18 Oct 15 08:43 link_inner2 -> ../sub2/inner2.txt

/root/demo/chown/tree/sub2:
total 4
-rw-r--r-- 1 u4d1 u4dgrp1 7 Oct 15 08:43 inner2.txt

💡 说明:入口是软链但想改真实目录时加 -H;若还想把软链自身的属主也一并修好,再补一条不带 -R 的 chown -h。

4.4 以参照文件为模板批量对齐

$ chown u4d2:u4dgrp2 /root/demo/chown/ref.txt

$ ls -l /root/demo/chown/ref.txt
-rw-r--r-- 1 u4d2 u4dgrp2 12 Oct 15 08:43 /root/demo/chown/ref.txt

$ chown u4d1:u4dgrp1 /root/demo/chown/b.txt

$ ls -l /root/demo/chown/b.txt
-rw-r--r-- 1 u4d1 u4dgrp1 13 Oct 15 08:43 /root/demo/chown/b.txt

$ chown --reference=/root/demo/chown/ref.txt /root/demo/chown/b.txt

$ ls -l /root/demo/chown/b.txt
-rw-r--r-- 1 u4d2 u4dgrp2 13 Oct 15 08:43 /root/demo/chown/b.txt

💡 说明:样本文件 ref.txt 设好一次,目标文件 b.txt 无论当前归属是什么(此处从 u4d1:u4dgrp1 一键对齐),一条 --reference 照抄成 u4d2:u4dgrp2,避免属主属组名打错。

4.5 一条命令完成"移交 + 收回"

$ chown -c u4d2:u4dgrp1 /root/demo/chown/a.txt
changed ownership of '/root/demo/chown/a.txt' from u4d1:root to u4d2:u4dgrp1

$ chown -c 0:0 /root/demo/chown/a.txt
changed ownership of '/root/demo/chown/a.txt' from u4d2:u4dgrp1 to 0:0

💡 说明:交接前先把文件给接手方(owner:group 一步到位),验收完毕收回 root。-c 的输出可直接粘进交接记录,from/to 两端把来龙去脉记得清清楚楚。

五、注意事项与常见问题

Q1:chown 改了属主,属组为什么也跟着变了? 大概率用了 owner: 或 owner.group 形式(冒号/点号结尾),属组会被重置为属主的登录组;或者目标端写成了 owner:group。只想改属主就只写属主名,别带任何分隔符(见 3.2 实测)。

Q2:普通用户执行 chown 报 Operation not permitted,文件明明是自己的? 改属主是内核 CAP_CHOWN 能力,只有 root(或具备该能力的进程)可以。普通用户能做的只有把属组改成自己所属的组之一(见 chgrp 篇实测)。需要"转赠"文件时让 root 执行,或用 install -o user -g group 重建文件。

Q3:chown -R 之后进入目录报 Permission denied? 属主变了但目录模式位可能没跟上(比如原来 700 且新属主无 x 权限)。chown 只改归属不改权限位,两者要配套:chown -R u4d1:u4dgrp1 dir && chmod -R u+rx dir。目录的 x 权限含义见 chmod 篇。

Q4:-R 会顺着软链把链接目标的文件也改了吗? 默认不会(-P 语义,只改软链本身,见 3.11 实验一)。显式 -R -L 才会全部穿透,且软链指到树外时树外文件也会被改到,慎用;"入口是软链"的场景用 -R -H。

Q5:为什么 chown -f 还报 invalid user? -f 抑制的是运行期错误(Operation not permitted 一类);用户名解析发生在参数处理阶段,属于程序自身的合法性检查,不受 -f 影响(见 3.8、3.14 两处实测)。

Q6:想把属主设成一个名字是纯数字的用户怎么办? chown 123 FILE 会被当成 uid=123。coreutils 的约定是给用户名补冒号消除歧义:chown '123:' FILE 表示名为 123 的用户(组取其登录组)。

Q7:批量改了几千个文件,怎么确认到底改了哪些? 用 -c(只打印变化行)或 -v(打印全部处理行),输出形如 changed ownership of '...' from A to B,可直接落日志审计(见 3.6、3.7 实测)。

六、参考链接