文件权限与属性 - Arch Linux 中文维基

跳转到内容

# 文件权限与属性

来自 Arch Linux 中文维基
翻译状态：

- 本文（或部分内容）译自 File permissions and attributes，最近一次同步于 2022-11-18，若英文版本有所更改，则您可以帮助同步与翻译更改的内容。
- 您可以在 ArchWiki 的对应页面找到本文翻译的原始修订历史。
- 本文可能与英文原文存在出入。

相关文章

- Users and groups
- umask
- Access Control Lists
- Capabilities

文件系统用权限和属性来规范系统进程与文件和目录之间的交互。

警告：权限和属性设置只能防范来自已经启动了的当前系统的攻击。为了防止数据被能物理访问该机器的人的接触，必须同时使用磁盘加密.

## 查看权限

使用ls命令的`-l`选项查看为目录内容设置的权限（或文件模式），例如：

    $ ls -l /path/to/directory

    total 128
    drwxr-xr-x 2 archie users  4096 Jul  5 21:03 Desktop
    drwxr-xr-x 6 archie users  4096 Jul  5 17:37 Documents
    drwxr-xr-x 2 archie users  4096 Jul  5 13:45 Downloads
    -rw-rw-r-- 1 archie users  5120 Jun 27 08:28 customers.ods
    -rw-r--r-- 1 archie users  3339 Jun 27 08:28 todo
    -rwxr-xr-x 1 archie users  2048 Jul  6 12:56 myscript.sh

第一栏是我们必须关注的内容。 以`drwxrwxrwx +`为例，每个字符的含义在下表中说明：

`d` | `rwx` | `rwx` | `rwx` | `+`
文件类型，技术上不属于其权限。 有关可能值的说明，请参阅 `info ls -n "What information is listed"` 命令的输出。 | 所有者对文件的权限，如下所述。 | 该组对该文件的权限，如下所述。 | 所有其他用户对该文件的权限，如下所述。 | 一个指定备用访问方法是否适用于该文件的字符。 当此字符是空格时，没有备用访问方法。 `.`字符表示具有安全上下文的文件，但没有其他备用访问方法。 具有任何其他备用访问方法的文件用`+`字符标记，例如在使用访问控制列表 (ACL) 的情况下.

权限三元组（也就是上面例子中的`rwx`）可以由以下字符（权限位）构成：

| 字符 | 文件效果 | 目录效果
--- | --- | --- | ---
读权限（第一个字符） | `-` | 不能读取该文件 | 不显示目录里的内容
`r` | 可以读取该文件 | 能显示目录里的内容
写权限（第二个字符） | `-` | 不能修改该文件 | 不能修改目录中的内容
`w` | 可以修改该文件 | 能修改目录中的内容（创建、重命名或删除文件或子目录）；需要同时设置执行权限，否则本权限无效。
执行权限（第三个字符） | `-` | 不能执行该文件 | 无法使用 cd 命令访问该目录
`x` | 可以执行该文件 | 能使用 cd 命令访问该目录。这是实践中唯一一个算是可以从父目录继承而来的权限。实际上，如果某文件或目录路径中的任何一个目录没有设置 x 权限， 就算最终访问的文件或目录设置了对应的权限也是打不开的。请参考path_resolution(7) 来了解更多。
`s` | 当出现在用户（所有者）权限三元组时，代表 setuid 位； 当出现在组权限三元组时，代表 setgid 位；不会出现在对其他用户权限的三元组中；同时意味着设置了 `x` 权限。
`S` | 与 `s` 相同，但是未设置 `x` 权限；普通文件中很少见，并且对于目录是无效的。
`t` | 粘滞位，只存在于对其他用户权限的三元组中；同时意味着设置了 `x` 权限。
`T` | 与 `t` 相同，但是未设置 `x` 权限 ；普通文件中很少见。

请参考 `info Coreutils -n "Mode Structure"` 和 chmod(1) 以获得更详细的说明。

提示：您可以用 `namei -l path` 命令查看文件或者目录沿路的权限

### 案例

让我们用一些案例来解释说明：

    drwx------ 6 archie archie  4096 Jul  5 17:37 Documents

Archie 具有对 `Document` 目录的完全访问权限。它可以列出、创建和重命名或删除 Documents 中的任何文件，无论其中文件的权限是什么。而它访问文件的能力取决于具体文件的权限。

    dr-x------ 6 archie archie  4096 Jul  5 17:37 Documents

Archie 拥有完全访问权限，但他们不能创建、重命名或删除任何文件。他们可以列出文件，并且（如果文件的权限允许）可以访问文档中的现有文件。

    d-wx------ 6 archie archie  4096 Jul  5 17:37 Documents

Archie 不能在 `files` 目录中执行 `ls` ，但是如果它知道现有文件的名称，就可以列出、重命名、删除或(如果文件的权限允许)访问该文件。此外，它们还能够创建新文件。

    d--x------ 6 archie archie  4096 Jul  5 17:37 Documents

Archie 只能够在文件权限允许的情况下访问已知的文件。它不能列出目录中的文件，也无法创建、重命名或者删除任何文件。

要记得，我们在此介绍的是目录权限，这与单个文件权限无关。创建一个新文件时，修改的是目录。这就是为什么您需要有目录的写权限。

接下来我们看一些文件权限方面的例子：

    -rw-r--r-- 1 archie web  5120 Jun 27 08:28 foobar

在这里，我们可以看到第一个字母不是 `d` 而是 `-`。所以我们知道它是一个文件，而不是一个目录。接下来，所有者的权限是`rw-`。所有者并没有拥有全部的三个权限可能很奇怪，但这个文件作为一个文本文件而不是一个可执行文件时，并不需要`x` 权限（但如果它包含 python 代码之类的内容，那么它很可能是可执行文件），我们可以用 Gedit、EMACS 等文本编辑器或者 R 之类的软件来读取它。该文件的组权限为 `r--` ，因此该组的成员可以读取文件，但不能以任何方式对其进行写入/编辑，实际上就是把它设置为只读。最后是对其他用户的权限，被设置为与组权限一致，也是只读。

## 修改权限

chmod 是 Linux 和其他 Unix-like 操作系统中用来修改文件或者目录权限的命令。

### 以字符形式修改权限

想要修改文件的权限（或者叫访问模式），请在终端里使用 chmod 命令。以下是该命令的基本结构：

    chmod who=permissions filename

其中的 `who` 是一个或者多个字母，代表要指定权限的对象，可以为：

- `u`: 拥有该文件的用户
- `g`: 该文件所属的用户组 .
- `o`: 所有其他用户
- `a`: 以上所有，等效于 `ugo`.

权限和上面 #查看权限所述的相同 (`r`, `w` 和 `x`).

现在看一下使用这个命令的一些示例。假设您对“文档”目录进行了严格的保护，并希望拒绝除您之外的所有人在其中读取、写入和执行(或在本例中是拒绝搜索或查看)的权限。

修改前： `drwxr-xr-x 6 archie web 4096 Jul 5 17:37 Documents`

    $ chmod g= Documents
    $ chmod o= Documents

修改后： `drwx------ 6 archie web 4096 Jul 6 17:32 Documents`

在这里，因为您想要禁止所有权限，所以不要在 `=` 后面输入任何内容。如此修改后，除了文件所有者的权限为 `rwx` 之外，其他权限都是 `-`。

您可以使用如下命令来恢复原来的状态：

再次修改前：`drwx------ 6 archie web 4096 Jul 6 17:32 Documents`

    $ chmod g=rx Documents
    $ chmod o=rx Documents

再次修改后：`drwxr-xr-x 6 archie web 4096 Jul 6 17:32 Documents`

在下一个例子中，您想给组及其他用户读取和执行权限，所以您可以在 `=` 后面输入相应的权限 `r` 和`x`，记得不要带空格。

您可以在 `who` 的地方输入多个字母，来同时给多个对象设置权限，如：

    $ chmod go=rx Documents

注意：`chmod` 命令中的 `who` 字母或者权限位（``）字符的顺序是无关紧要的。`chmod go=rx file` 和 `chmod og=xr file` 这两个命令的含义完全相同

接下来我们考虑第二个例子，假设您想让自己和 `web` 用户组中的用户（可能是您的同事）有 `foobar` 这个文件的读写权限， 但其他人只能读取它。那么操作如下：

修改前： `-rw-r--r-- 1 archie web 5120 Jun 27 08:28 foobar`

    $ chmod g=rw foobar

修改后：`-rw-rw-r-- 1 archie web 5120 Jun 27 08:28 foobar`

这与第一个示例完全相同，但使用的是文件，而不是目录，并且您授予的是写入权限（这只是为了给出授予每个权限的示例）。

#### 字符形式的捷径

chmod 命令允许使用 `+` 或 `-` 而不是`=`从现有集合中添加和减去权限。这与上面的命令不同，后者实质上是重设权限(例如，要将权限从`r--`更改为`rw-` ，您仍然需要在 chmod 命令的`=`之后包含 `r` 和 `w`。如果遗漏了`r` ，那么在使用`=`重设权限时，它将取消`r`的权限。使用`+`和`-`可以通过添加或删除当前的权限集来避免这种情况)。

让我们用 `+` 和 `-` 的方式复现一下前面给组添加写权限的例子：

修改前： `-rw-r--r-- 1 archie web 5120 Jun 27 08:28 foobar`

    $ chmod g+w foobar

修改后：`-rw-rw-r-- 1 archie web 5120 Jun 27 08:28 foobar`

另一个例子，取消所有用户和组的写入权限。

修改前： `-rw-rw-r-- 1 archie web 5120 Jun 27 08:28 foobar`

    $ chmod a-w foobar

修改后： `-r--r--r-- 1 archie web 5120 Jun 27 08:28 foobar`

另一个不同的捷径是特殊的 `X` 模式：实际上不存在这个模式，但它通常与 `-R` 选项（递归）一起使用，以设置只针对目录的执行权限，而不修改常规文件的权限，例如:

    $ chmod -R a+rX ./data/

#### 复制权限

您可以让 chmod 把某对象（比如所有者）的权限复制给其他对象（比如组或者所有人）。想要做到这一点，在 `=` 后面不要跟权限（`r`、`w`和`x`），而是输入另一个 who 字母。比如：

修改前 `-rw-r--r-- 1 archie web 5120 Jun 27 08:28 foobar`

    $ chmod g=u foobar

修改后 `-rw-rw-r-- 1 archie web 5120 Jun 27 08:28 foobar`

这个命令的意思就是“把对组(`g=`)的权限设置为与所有者(`=u`)的权限相同”。请注意，您不能复制一组权限，也不能授予新的权限，以下是错误示范，chmod 会报错：

    $ chmod g=wu foobar

### 数字形式

chmod 也可以用数字来设置权限。

使用数字是另一种方法，它允许您同时编辑所有者、组和其他人的权限，以及setuid、setgid和粘滞位。命令的基本结构如下：

    $ chmod xxx filename

`xxx` 部分是一个三位数，其中的每一位可以是0到7之间的任何数字。第一位数字指所有者的权限，第二位数字指组的权限，而第三位数字指所有其他人的权限。

在这个数字表示法中，权限 `r`、`w`和`x`所对应的数值是:

    r=4
    w=2
    x=1

要得到这个三位数，您要考虑为所有者、组和所有其他人设置哪些权限，然后将其对应的数值累加起来。例如，如果希望授予目录的所有者读写和执行权限，并希望 group 和其他所有人只有读写权限，那么通过计算可以得到如下数值：

- 所有者: `rwx`=4+2+1=7
- 组: `r-x`=4+0+1=5
- 其他人: `r-x`=4+0+1=5

    $ chmod 755 filename

这就相当于使用如下命令：

    $ chmod u=rwx filename
    $ chmod go=rx filename

若要以数字形式查看文件或目录的现有权限，请使用stat(1)命令：

    $ stat -c %a filename

`%a` 指定以数字形式输出文件权限。

大多数目录被设置为 `755` 以允许所有者读取、写入和执行，但拒绝被其他所有人写入；文件通常是`644` 以允许所有者读取和写入，但允许其他所有人读取；请参考最后一个关于不可执行文件缺少`x`权限的说明，此处同理。

为了用实例来说明这一点，我们用数字方式复现一下前面举过的例子：

修改前：`-rw-r--r-- 1 archie web 5120 Jun 27 08:28 foobar`

    $ chmod 664 foobar

修改后： `-rw-rw-r-- 1 archie web 5120 Jun 27 08:28 foobar`

如果这是一个可执行文件，同时您想向所有者和组授予可执行权限，则权限数字为`774`。或者，如果您希望每个人都只具有读取权限，则数字将为`444`。将`r`视为4，`w`视为2，以及`x`视为1，这可能是计算`chmod xxx 文件名`的权限数值最简单的方法。

但还有一种二进制方法，其中每个权限都代表一个二进制数，最后再将其转换为一个数字。它有点复杂，但为了完整起见，在此也介绍该方法。

对于以下权限组合：

    -rwxrwxr-x

如果您在每个授予的权限下写1，而在每个未授予的权限下写0，则结果如下：

    -rwxrwxr-x
     111111101

然后把它当成二进制数进行转换：

    000=0	    100=4
    001=1	    101=5
    010=2	    110=6
    011=3	    111=7

因此，上述值为775。

如果我们想从组中删除写权限：

    -rwxr-xr-x
     111101101

因此，该值将为755，您可以使用 `chmod 755 文件名`删除可写权限。无论使用哪种方法，您最终都会得到相同的三位数。使用文本还是数字取决于个人偏好和打字速度。如果您希望将目录或文件还原为默认权限（例如所有者有读写和执行权限，但拒绝其他所有人的写权限），则使用`chmod 755/644 文件名`可能会更快。但如果您要将权限更改为比较少见的组合，则使用文本方法可能会更简单、更快，而不是尝试将其转换为数字，这可能会导致错误。对于只需要偶尔使用chmod的用户来说，这两种方法的速度都没有显著的差异。

您也可以用数字形式设置`setuid`, `setgid` 和 `sticky` 权限位。

    setuid=4
    setgid=2
    sticky=1

比如 `chmod 2777 filename` 将为每个人设置读/写/可执行位，并启用`setgid`位。

### 批量 chmod

通常，目录和文件不应具有相同的权限。如果需要批量修改目录树，请使用find选择性地修改其中一个或另一个。

若要只把目录权限修改为 755：

    $ find directory -type d -exec chmod 755 {} +

若要只把文件权限修改为 644：

    $ find directory -type f -exec chmod 644 {} +

## 修改所有者

chown 能够修改文件或者目录的所有者，这在某些情况下会更简单快捷。

比如，您要使用GParted为备份数据创建一个新分区。Gparted以root身份执行所有操作，因此默认情况下所有内容都属于root。这一切都很好，但当要向挂载的分区写入数据时，常规用户会没有权限。

    brw-rw---- 1 root disk 8,    9 Jul  6 16:02 sda9
    drwxr-xr-x 5 root root    4096 Jul  6 16:01 Backup

若您所见，`/dev`是由root所有的，而挂载点(`/media/Backup`也是一样。如果我们要修改挂载点的所有者，您可以执行如下命令：

修改前： `drwxr-xr-x 5 root root 4096 Jul 6 16:01 Backup`

    # chown archie /media/Backup

修改后： `drwxr-xr-x 5 archie root 4096 Jul 6 16:01 Backup`

现在在无需调整权限的情况下，这个分区就可以由新的所有者 archie 写入了。（作为所有者，它本身就拥有 `rwx` 权限）

注意：

- `chown` 总是会清除 setuid 和 setgid 权限位
- 非 root 用户不能使用 `chown` 来把他们自己拥有的文件“送给”其他用户

## 访问控制列表（ACL）

Access Control Lists 通过允许为任何用户或组设置对任何文件的权限，为文件系统提供了额外的、更灵活的权限机制。

## Umask

umask 实用程序用于控制文件创建模式掩码，该掩码确定了新创建文件的权限位的初始值。

## 文件属性

除了控制用户和组读、写和执行权限的文件权限之外，还有几个文件系统支持文件属性，这些属性可以进一步自定义允许的文件操作。

警告：默认情况下， cp、rsync 和其他类似的程序不会保留文件属性

e2fsprogs包 软件包内有 lsattr(1) 和 chattr(1) 这两个可以列出和修改文件属性的工具。

以下是一些有用的属性，但并非所有的文件系统都支持每个属性。

- `a` - 仅追加（append only）：文件只能以追加的方式打开。
- `c` - 压缩（compressed）：为文件启用文件系统级的压缩。
- `i` - 不变（immutable）：无法被修改、删除、重命名或创建指向它的链接。只能由root用户设置。
- `j` - 数据日志（data journaling）：为文件的写入和元数据启用日志。
- `m` - 不压缩（no compression）：为文件禁用文件系统级的压缩。
- `A` - 禁用atim更新（no atime update）：文件的 atime （访问时间）将不会被修改。
- `C` - 禁用写时拷贝（no copy on write）: 对于支持写时拷贝的文件系统，禁用写时拷贝。

查看 chattr(1) 以获得更详细的文件属性列表以及它们的作用。

比如，如果您想给某个文件设置不变（immutable）属性，使用如下命令：

    # chattr +i /path/to/file

要删除文件上的属性，只需把 `+` 改为 `-`。

## 扩展属性

根据 xattr(7)：“扩展属性是与文件和目录永久关联的键值对”。有四个扩展属性类: security、 system、 trust 和 user。

警告：默认情况下，cp、rsync 和其他类似的程序不会保留文件属性。请参考 #保留扩展属性.

扩展属性还用于设置能力（Capabilities）.

### 用户扩展属性

用户扩展属性可用于存储有关文件的任意信息，比如：

    $ setfattr -n user.checksum -v "3baf9ebce4c664ca8d9e5f6314fb47fb" foo.txt

使用getfattr来显示扩展属性：

    $ getfattr -d foo.txt

    # file: foo.txt
    user.checksum="3baf9ebce4c664ca8d9e5f6314fb47fb"

如果要删除扩展属性：

    $ setfattr -x user.checksum foo.txt

### 保留扩展属性

命令 | 所需的选项
--- | ---
`cp` | `--preserve=mode,ownership,timestamps,xattr`
`mv` | 默认会保留[注 1]
`tar` | 创建tar档时用 `--xattrs` ，解压时用 `--xattrs-include='*'`
`bsdtar` | 解压时用 `-p`
rsync | `--xattrs`

1. ↑ 当目标文件系统不支持扩展属性时，mv 会静默地丢弃这些扩展属性。

要在使用文本编辑器的时候保留扩展属性，您需要把他们配置为在保存时截断（truncate）文件而非使用 rename(2).[1]

## 技巧和窍门

### Preserve root

使用 `--preserve-root` 选项来阻止 `chmod` 递归地从 `/` 修改文件权限。 这可以防止在系统范围内删除可执行位，从而破坏系统。要每次使用此标志，请在alias中设置它。参见 [2].

## 参见

- wikipedia:Chattr
- Linux 文件权限的困惑
- Linux 文件权限的困惑第二部分
- wikipedia:Extended file attributes#Linux
- 扩展属性：好，不太好，坏。
- 在 Linux 中备份和恢复文件权限
- 为什么 “chmod -R 777 /” 具有破坏性？
- Unix 中用户私有组的方式和原因

分类：​

- 文件系统
- 命令行

文件权限与属性
添加话题