Linux 常见文件/文件夹操作后,权限会如何变化

理解 Linux 文件权限,不能只看 chmod。很多日常操作,比如 touchmkdircpmvrm、解压、同步、编辑文件,都会直接或间接影响文件的权限、属主、属组、ACL 或特殊权限位。

这篇文章从常见操作出发,具体说明 Linux 文件和文件夹在被创建、复制、移动、删除、编辑、压缩解压、同步之后,权限通常会发生什么变化。

一、先理解 Linux 权限到底记录在哪里

Linux 中每个文件或目录都有一组元数据,主要包括:

ls -l

示例:

-rw-r--r-- 1 user user  1234 Jun  6  test.txt
drwxr-xr-x 2 user user  4096 Jun  6  docs

第一列就是权限信息。以 -rw-r--r-- 为例:

-     rw-     r--     r--
类型  所有者  所属组  其他人

其中:

位置 含义
- 普通文件
d 目录
l 符号链接
r read,读权限
w write,写权限
x execute,执行权限

对文件来说:

权限 含义
r 可以读取文件内容
w 可以修改文件内容
x 可以执行文件

对目录来说,含义稍微不同:

权限 含义
r 可以列出目录下的文件名
w 可以在目录内创建、删除、重命名文件
x 可以进入目录,访问目录内文件的元数据或内容

目录的 x 权限非常重要。没有 x,即使有 r,也很难正常进入和访问目录。

二、权限变化的核心规则:新建看 umask,已有文件通常不变

Linux 中一个非常核心的规则是:

新建文件或目录时,权限通常由”默认权限 – umask”决定;修改已有文件内容时,权限通常不会变化。

可以查看当前 umask:

umask

常见结果是 0022,这意味着系统会从默认权限中减去对应权限。

Linux 创建新对象时,默认权限一般是:

类型 原始默认权限
普通文件 666,即 rw-rw-rw-
目录 777,即 rwxrwxrwx

为什么普通文件默认不是 777?因为 Linux 不希望新建的普通文件天然可执行。一个脚本文件即使内容是 shell 脚本,也通常需要手动 chmod +x script.sh 才会变成可执行文件。

如果 umask 是 022,那么新建结果通常是:

  • 文件:666 – 022 = 644 → rw-r--r--
  • 目录:777 – 022 = 755 → rwxr-xr-x

所以,理解权限变化,首先要理解 umask

三、touch:创建新文件会受 umask 影响,已有文件权限不变

touch 有两种常见情况。

1. 文件不存在时

touch a.txt

这会创建一个新文件。如果当前 umask 是 022,新文件通常是 -rw-r--r-- a.txt,也就是 644。原因是:普通文件默认权限 666,减去 umask 022,得到 644。

2. 文件已经存在时

touch a.txt

如果 a.txt 已经存在,touch 默认只是更新时间戳,不会改变文件权限。例如原来是 -rw------- a.txt,再次执行 touch a.txt 后,权限仍然是 -rw------- a.txt

touch 创建新文件时会产生权限;touch 更新已有文件时通常不改变权限。

四、mkdir:新建目录会受 umask 影响

mkdir docs

如果 umask 是 022,目录通常是 drwxr-xr-x docs,也就是 755。原因是:目录默认权限 777,减去 umask 022,得到 755。

如果希望指定目录权限,可以使用:

mkdir -m 700 private

结果一般是 drwx------ private,表示只有目录所有者可以进入、查看和修改该目录。

注意:目录权限比文件权限更容易影响实际访问。如果 docs 是目录,chmod 600 docs 通常会导致你无法正常进入目录,因为目录没有 x 权限。

对于目录,常见权限是:

权限 含义
700 只有自己可访问
755 自己可写,别人可进入和读取
775 自己和同组用户可写,别人可读可进入
777 所有人可写,不安全,除非配合 sticky bit

五、重定向:> 创建新文件受 umask 影响,覆盖已有文件不改变权限

Shell 重定向也会影响文件权限。

1. 文件不存在时

echo "hello" > a.txt

如果 a.txt 不存在,Shell 会创建它。新文件权限通常与 touch 类似,也受 umask 影响。在 umask 022 下,通常是 -rw-r--r-- a.txt

2. 文件已经存在时

echo "new content" > a.txt

这会清空原内容并写入新内容,但通常不会改变文件权限。例如原来是 -rw------- a.txt,执行覆盖写入后,仍然是 -rw------- a.txt

> 创建新文件时,权限由 umask 决定;> 覆盖已有文件时,一般只改内容,不改权限。

3. >> 追加内容也不改变已有文件权限

echo "more" >> a.txt

如果文件已经存在,追加内容通常不改变权限。如果文件不存在,则会新建文件,权限仍然受 umask 影响。

六、cp:复制文件时,目标文件权限不一定完全等于源文件

cp 是最容易让人误解的操作之一。

1. 复制到一个不存在的新文件

cp source.txt target.txt

如果 target.txt 不存在,系统会创建一个新文件。一般来说,目标文件会参考源文件权限,但也可能受到当前用户的 umask 影响。普通复制通常不保证完整保留所有元数据。

2. 复制到已经存在的文件

cp source.txt target.txt

如果 target.txt 已经存在,cp 通常会覆盖其内容,但保留 target.txt 原来的权限。这是因为目标文件已经存在,cp 只是打开它、截断它、写入新内容,而不是重新创建一个权限全新的文件。

3. 使用 cp -p 保留权限和时间戳

cp -p source.txt target.txt

-p 表示 preserve,会尽量保留:权限 mode、时间戳、属主属组(前提是当前用户有权限保留)。普通用户通常不能随便把文件属主设置成其他人,所以属主未必能完整保留。

4. 使用 cp -a 归档复制

cp -a source_dir target_dir

-a 类似”尽可能原样复制”,常用于复制目录。它会尽量保留:文件权限、目录权限、符号链接、属主属组、时间戳、硬链接关系、扩展属性和安全上下文(视系统支持情况而定)。

如果你想复制一个目录,并希望权限尽量不变,通常用 cp -a old_dir new_dir,而不是简单地 cp -r old_dir new_dir

七、mv:同一文件系统内移动,权限通常完全不变

mv 有两种情况。

1. 同一文件系统内移动或重命名

mv a.txt b.txt
mv a.txt /home/user/docs/

如果源和目标在同一个文件系统内,mv 本质上只是改目录项,也就是改变文件”放在哪里”或”叫什么名字”。文件本身的 inode 没变,所以权限、属主、属组、ACL、时间戳等通常都不变

2. 跨文件系统移动

mv a.txt /mnt/usb/

如果源和目标不在同一个文件系统,mv 实际上更接近复制 + 删除原文件。这时权限一般会尽量保留,但可能受以下因素影响:当前用户权限、目标文件系统是否支持 Linux 权限、是否能保留属主属组、是否支持 ACL 和扩展属性、是否是 FAT32/exFAT/NTFS 等非原生 Linux 文件系统。

同一文件系统内 mv,权限几乎肯定不变;跨文件系统 mv,权限可能发生变化。

八、rm:删除文件不看文件自己的写权限,而看目录权限

很多人以为删除文件需要文件本身有写权限,其实不完全对。

删除一个文件,本质上是修改它所在目录的目录项。所以你是否能删除文件,主要看你对其父目录有没有 w + x(写权限和进入权限)。

例如,-r-------- a.txt(文件本身没有写权限),但如果你对它所在目录有写权限和执行权限,你仍然可能删除它。反过来,如果文件本身是 -rw-rw-rw- a.txt,但你对它所在目录没有写权限,你也不能删除它。

sticky bit 的特殊情况

比如 /tmp 目录通常是 drwxrwxrwt /tmp,最后的 t 就是 sticky bit。在这种目录下,即使大家都有写权限,也不是谁都可以删除别人的文件。通常只有以下用户可以删除:文件所有者、目录所有者、root。所以 /tmp 可以让大家创建临时文件,但不能随便删别人的文件。

九、chmod:直接改变权限

chmod 是最直接修改权限的命令。

1. 数字方式

chmod 644 a.txt
chmod 755 script.sh
chmod 700 private_dir

常见数字含义:

数字 权限
7 rwx
6 rw-
5 r-x
4 r–
0

2. 符号方式

chmod u+x script.sh
chmod g-w a.txt
chmod o-r secret.txt
chmod a+r readme.md

含义:

符号 含义
u user,所有者
g group,所属组
o others,其他人
a all,所有人

3. 递归修改目录要小心

chmod -R 755 mydir

这会把目录下所有文件和子目录都改成 755。问题是:普通文本文件也会被加上执行权限。更合理的写法通常是:

find mydir -type d -exec chmod 755 {} \;
find mydir -type f -exec chmod 644 {} \;

这样目录是 755,普通文件是 644。如果只想给目录加执行权限,可以使用大写 X:

chmod -R a+X mydir

X 的意思是:只给目录加执行权限,或者给原本已经有执行权限的文件加执行权限。这比小写 x 更安全。

十、chown 和 chgrp:改变属主属组,也可能影响特殊权限

文件除了权限位,还有属主和属组。

ls -l
# 输出示例:-rw-r--r-- 1 alice staff 1234 Jun 6 a.txt

其中 alice 是属主,staff 是属组。

修改属主:sudo chown bob a.txt
修改属组:chgrp developers a.txt
同时修改:sudo chown bob:developers a.txt
递归修改目录:sudo chown -R bob:developers project/

注意:修改属主或属组时,系统可能会清除 setuid、setgid 等特殊权限位。这是出于安全考虑,防止通过改变属主制造提权风险。

十一、编辑文件:通常权限不变,但要看编辑器如何保存

用编辑器修改文件,例如 vim a.txtnano a.txt,通常情况下,保存后文件权限不会变化。

但是有些工具并不是”原地修改”,而是:创建临时文件 → 写入新内容 → 用新文件替换旧文件。这种情况下,可能出现 inode 变化、硬链接关系断开、ACL 丢失、扩展属性丢失、权限被重新计算、属主属组发生变化等问题。

尤其是在使用 sudo vim a.txt 编辑普通用户文件时,更要小心。如果编辑器或保存方式不当,可能导致文件属主变成 root。更安全的做法通常是使用 sudoedit a.txtsudo -e a.txt

十二、硬链接和符号链接:权限变化逻辑不同

1. 硬链接

ln a.txt b.txt

a.txt 和 b.txt 指向同一个 inode。所以它们不是两个独立文件,而是同一个文件的两个名字。对其中一个执行 chmod 600 a.txt,另一个也会显示为 -rw------- b.txt。因为权限属于 inode,而不是属于文件名。硬链接之间共享同一套权限。

2. 符号链接

ln -s a.txt link.txt

符号链接本身经常显示为 777,但这个权限通常没有实际意义。真正起作用的是目标文件 a.txt 的权限。很多情况下,chmod 600 link.txt 实际修改的是目标文件 a.txt 的权限,而不是链接本身。

符号链接的显示权限通常不重要,真正重要的是目标文件权限。

十三、压缩和解压:tar 通常更能保留权限,zip 不一定

1. tar

tar -cf archive.tar mydir   # 打包
tar -xf archive.tar          # 解包

tar 会记录文件权限信息。但是解压时实际权限可能受到以下因素影响:当前用户权限、当前 umask、是否使用 root 解压、是否使用保留权限参数、文件系统是否支持权限、archive 内是否记录了属主属组。

如果想尽量保留权限,可以使用 tar --same-permissions -xf archive.tar。常见备份命令会用:

sudo tar --xattrs --acls -cpf backup.tar /some/dir

2. zip / unzip

zip 也可以保存一部分 Unix 权限信息,但它的跨平台属性更强。如果 zip 文件来自 Windows,里面可能没有完整的 Linux 权限信息。解压后经常出现可执行权限丢失等问题。

如果是在 Linux 系统之间备份、迁移文件,通常优先考虑 tar 或 rsync,而不是 zip。

十四、rsync:是否保留权限,关键看参数

普通用法:

rsync source.txt remote:/path/

这种情况下,权限可能受目标端 umask 影响。

更常见的是使用归档模式:

rsync -a source_dir/ target_dir/

-a 表示 archive,会尽量保留:权限、符号链接、时间戳、递归目录、属主属组(前提是有权限)。如果是 root 执行,保留信息更完整。

如果希望同步时调整权限,可以使用:

rsync -a --chmod=Du=rwx,Dgo=rx,Fu=rw,Fgo=r source/ target/

这里:

写法 含义
D directory,目录
F file,文件
u 所有者
g 所属组
o 其他人

这个命令的意思大致是:目录 755,文件 644。适合部署网站、同步项目文件。

十五、scp / sftp:远程复制时,权限可能受远程 umask 影响

scp a.txt user@server:/path/

目标文件的权限可能受远程服务器的 umask 影响。如果想保留原文件的时间和权限,可以使用:

scp -p a.txt user@server:/path/

-p 表示 preserve,会保留修改时间、访问时间和权限模式。不过它对属主属组的保留能力有限,因为远程用户通常不能随意创建属于别人的文件。如果你需要更可靠地同步权限,通常建议使用 rsync -a,而不是普通 scp。

十六、git:不会完整保存 Linux 权限,只保存可执行位

很多人以为 Git 会完整保存文件权限,其实不是。Git 通常只关心:普通文件是否可执行,也就是大致区分 644 普通文件和 755 可执行文件。

chmod +x run.sh
git add run.sh
git commit -m "make run.sh executable"

Git 会记录它是可执行文件。但是 Git 不会完整记录:文件属主、文件属组、ACL、setuid、setgid、sticky bit、复杂权限组合。

如果你需要保存完整 Linux 权限,不应该只依赖 Git。

十七、ACL:会让权限变化比 chmod 更复杂

除了传统的 rwx 权限,Linux 还支持 ACL。

查看 ACL:getfacl a.txt
设置 ACL:setfacl -m u:bob:rw a.txt(给用户 bob 单独增加读写权限)

目录还可以设置默认 ACL:

setfacl -m d:g:developers:rwx project/

这表示在 project/ 目录中新建的文件或子目录,会继承某些 ACL 规则。

一旦目录设置了默认 ACL,新建文件的权限结果就不再只是简单的”默认权限 – umask”,而是会受到默认 ACL 影响。所以有时你会发现 touch a.txt 生成的权限和你根据 umask 推算的不一样,这时就应该检查 getfacl .getfacl a.txt

十八、setuid、setgid、sticky bit:特殊权限位也会受操作影响

1. setuid

显示为 -rwsr-xr-x。它主要用于可执行文件。当用户执行这个程序时,进程会临时获得文件所有者的身份。典型例子是 /usr/bin/passwd。这类权限非常敏感。复制、修改属主、普通用户写入文件时,系统可能会清除 setuid 位,防止安全风险。

2. setgid

对于文件,setgid 类似 setuid,但对应的是组身份。对于目录,setgid 更常见。例如 chmod g+s project,查看为 drwxrwsr-x project。这表示在 project 目录中新建的文件或目录,会倾向于继承 project 的属组。这在团队协作目录中很有用。

3. sticky bit

常见于 /tmpdrwxrwxrwt /tmp。它的作用是:即使目录所有人可写,用户也不能随便删除别人的文件。共享临时目录经常需要 sticky bit。设置方式:chmod +t shared_tmpchmod 1777 shared_tmp

十九、挂载不同文件系统:权限表现可能完全不同

如果文件位于 Linux 原生文件系统(如 ext4、xfs、btrfs),那么权限、属主、属组、ACL 等通常可以正常保存。但如果是 FAT32、exFAT、NTFS,情况就复杂了。

这些文件系统本身不一定按 Linux 的方式保存权限。于是 Linux 可能通过挂载参数”模拟”权限。例如:

mount -o uid=1000,gid=1000,fmask=0133,dmask=0022 /dev/sdb1 /mnt/usb

其中:

参数 含义
uid 指定文件显示为哪个用户所有
gid 指定文件显示为哪个组所有
fmask 文件权限掩码
dmask 目录权限掩码

所以在 U 盘、移动硬盘、Windows 分区上,你看到的权限未必是真实写入文件系统的权限,而可能是挂载时计算出来的显示结果。

二十、常见操作后的权限变化总结

操作 权限是否变化 主要规则
touch 新文件 会产生新权限 受 umask 影响
touch 已有文件 通常不变 只更新时间戳
mkdir 会产生新权限 目录默认 777 减 umask
echo > 新文件 会产生新权限 受 umask 影响
echo > 已有文件 通常不变 只覆盖内容
echo >> 已有文件 通常不变 只追加内容
cp 到新文件 可能变化 参考源权限,但可能受 umask 和参数影响
cp 覆盖已有文件 通常保留目标原权限 内容变,权限不一定变
cp -p 尽量保留 保留权限、时间戳等
cp -a 尽量完整保留 适合复制目录
mv 同文件系统 不变 只是改名字或位置
mv 跨文件系统 可能变化 类似复制再删除
rm 不改变权限 删除取决于父目录权限
chmod 改变 直接修改权限
chown 改变属主 可能清除特殊权限位
chgrp 改变属组 可能影响协作权限
tar 解压 可能保留 受参数、umask、用户身份影响
zip 解压 不一定保留 跨平台时容易丢失权限
rsync -a 尽量保留 同步目录推荐
scp 可能变化 受远程 umask 影响
scp -p 尽量保留模式和时间 但属主属组有限
git clone 不完整保留 主要保存可执行位

二十一、几个典型场景

场景一:为什么我新建的文件是 644,目录是 755?
因为你的 umask 很可能是 022。文件:666 – 022 = 644;目录:777 – 022 = 755。可以查看 umask,临时修改 umask 077 后新建文件和目录通常变成 600 和 700,适合更私密的环境。

场景二:为什么复制文件后权限没有完全一样?
因为普通 cp 不一定完整保留所有元数据。如果希望尽量保留权限,使用 cp -p file1 file2;复制目录时使用 cp -a dir1 dir2

场景三:为什么我没有文件写权限,却能删除它?
因为删除文件看的是父目录权限。只要你对父目录有 w + x,就可能删除其中的文件。但如果目录有 sticky bit(例如 /tmp),就不能随便删除别人的文件。

场景四:为什么移动文件后权限没变?
如果是同一文件系统内 mv a.txt b.txt,这只是改名字,文件本身没变,所以权限不变。如果跨磁盘、跨分区、移动到 U 盘,就可能变。

场景五:为什么脚本从 Git 拉下来后不能执行?
可能是 Git 没记录可执行位,或者可执行位没有正确提交。可以执行 chmod +x script.sh 然后提交。但如果文件所在分区以 noexec 挂载,即使有 x 权限也不能直接执行。

二十二、实用检查命令

用途 命令
查看权限 ls -l
查看目录自身权限 ls -ld dirname
查看 inode ls -li
查看当前 umask umask
查看 ACL getfacl filename
查看挂载参数 mountfindmnt
查看文件系统类型 df -T
查看文件详细状态 stat filename

stat a.txt 会显示:Access(权限)、Uid、Gid、Modify、Change、Birth。其中 Change 是元数据变化时间,比如权限、属主、属组改变时会更新。

二十三、实用建议

日常使用中,可以记住几条经验:

  1. 新建文件的权限主要看 umask。
  2. 修改已有文件内容通常不改变权限。
  3. 复制文件不一定完整保留权限,想保留权限用 cp -p 或 cp -a。
  4. 同一文件系统内移动文件,权限通常不变。
  5. 删除文件主要看父目录权限,而不是文件自己的写权限。
  6. 目录的 x 权限非常关键,没有 x 就很难进入和访问。
  7. 压缩备份 Linux 文件时,优先考虑 tar 或 rsync -a。
  8. U 盘、NTFS、exFAT 分区上的权限可能是挂载参数模拟出来的。
  9. 团队协作目录可以考虑 setgid 和默认 ACL。
  10. 遇到权限异常时,不只看 ls -l,还要看 getfacl、stat、findmnt、umask。

结语

Linux 文件权限的变化并不是只有 chmod 才会发生。很多看似普通的操作,比如复制、解压、同步、远程传输、跨分区移动,都会影响最终权限。

最核心的判断思路是:

  • 如果是新建对象:看 umask、默认 ACL、挂载参数。
  • 如果是修改已有文件:权限通常不变。
  • 如果是复制或迁移:看命令参数是否保留元数据。
  • 如果是删除或重命名:看父目录权限。
  • 如果权限表现异常:检查 ACL、特殊权限位和文件系统挂载方式。

掌握这套逻辑后,再遇到”为什么这个文件权限变了”或”为什么我删不掉/执行不了/访问不了”这类问题,就能比较快地定位原因。

© 版权声明
THE END
喜欢就支持一下吧
点赞2 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容