使用Python更改文件权限

108

我想尝试更改文件的访问权限:

os.chmod(path, mode)

我想把它设为只读:

os.chmod(path, 0444)

是否有其他方法使文件只读?


我见过一些像S_IRUSR这样的东西..它是如何工作的??? - Abul Hasnat
我认为这只是设置一个位,所以当你或他们在一起时,你会得到0444。 - Joran Beasley
@AbulHasnat。你有解决方案吗? - avinash
9个回答

100
os.chmod(path, stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH)

stat

下面的标志也可以在os.chmod()的模式参数中使用:

stat.S_ISUID 设置UID位。

stat.S_ISGID 设置组ID位。这个标志有几个特殊用途。对于一个目录,它表示该目录应该使用BSD语义:在该目录创建的文件继承它们的组ID不是从创建进程的有效组ID中获取,而是从该目录中获取,并且在该目录中创建的目录也将设置S_ISGID位。对于没有设置组执行位(S_IXGRP)的文件,设置组ID位表示强制文件/记录锁定(另请参见S_ENFMT)。

stat.S_ISVTX 粘性位。当该位在一个目录上设置时,意味着只有该文件的所有者、该目录的所有者或特权进程才能重命名或删除该目录中的文件。

stat.S_IRWXU 文件所有者权限的掩码。

stat.S_IRUSR 所有者具有读取权限。

stat.S_IWUSR 所有者具有写入权限。

stat.S_IXUSR 所有者具有执行权限。

stat.S_IRWXG 组权限的掩码。

stat.S_IRGRP 组具有读取权限。

stat.S_IWGRP 组具有写入权限。

stat.S_IXGRP 组具有执行权限。

stat.S_IRWXO 其他人(不在组中)权限的掩码。

stat.S_IROTH 其他人具有读取权限。

stat.S_IWOTH 其他人具有写入权限。

stat.S_IXOTH 其他人具有执行权限。

stat.S_ENFMT System V文件锁定强制执行。此标志与S_ISGID共享:对于没有设置组执行位(S_IXGRP)的文件,强制执行文件/记录锁定。

stat.S_IREAD Unix V7的S_IRUSR同义词。

stat.S_IWRITE Unix V7的S_IWUSR同义词。

stat.S_IEXEC Unix V7的S_IXUSR同义词。


12
stat 中的常量只是为了方便阅读而设定的。S_IRUSR 是 0400, S_IRGRP 是 040, S_IROTH 是 4;将它们与按位 OR 结合可得到 0444。虽然您也可以将它们相加,但在一般情况下,使用按位 OR 是正确的选择,因为即使存在重叠的位,它也能正常工作(例如 0444 OR 0444 仍然是 0444,而相加会导致不同且错误的值)。 - tripleee
使用 + 似乎也可以代替 |。我不知道为什么要使用其中一个而不是另一个。 - Brōtsyorfuzthrāx
1
这里没有解释,你必须阅读注释或链接才能理解,除非你已经知道stat的作用。稍微解释一下会让它更好理解。 - DonyorM
2
@Shule 当从两个位掩码中组合位时,使用 | 更为适当。然而,如果每个掩码只有一个单独的位设置,就像上面答案中的所有常量一样,则 + 是等效的。 - ws_e_c421
1
在操作现有模式时,必须小心使用 +。如果已经设置了模式,则 + 不起作用,但 | 会起作用。例如,mode = stat.S_IWUSR + stat.S_IRUSR; ... some code ...; mode = mode + stat.S_IWUSR; 将不起作用,但最后一个命令会使用 | 起作用。 - mxmlnkn
好的,那么我们如何设置其中一个而不破坏其他所有内容呢? - Alex Jansen

57

只需在八进制中包含权限整数(适用于Python 2和Python3):

os.chmod(path, 0o444)

49

os.chmod(path, 0444) 在Python 2.x中更改文件权限的命令。如果要使用Python 2和Python 3的组合解决方案,将0444更改为0o444

您始终可以使用Python调用chmod命令,使用subprocess。不过我认为这只适用于Linux。

import subprocess

subprocess.run(['chmod', '0444', 'path'])

这在另一台服务器上的文件上不起作用。你能为那种情况提供建议吗?谢谢。 - Neo
一种与版本无关的生成八进制数的方法是: int("444", 8) 但请注意,另一个答案建议使用在stat模块中定义的符号值可能更加简洁。 - Isac Casapu
在无法找到通过Python的os.chmod快速执行chmod u+x的方法后,我选择了使用subprocess.run(...)路线来简化操作。也许这只是不支持与八进制符号表示法相比。 - Taylor D. Edmiston
os.system("chmod u+x /PATH/TO/YOUR/FILE")是什么意思? - user20068036

21

所有当前的答案都破坏了非写入权限:它们使得文件对任何人都是可读但不可执行的。当然,这是因为最初的问题要求使用444权限--但我们可以做得更好!

以下是一种解决方案,它保留了所有单独的“读取”和“执行”位。我编写了详细的代码以便于理解;如果您愿意,您可以将其更加简洁。

import os
import stat

def remove_write_permissions(path):
    """Remove write permissions from this path, while keeping all other permissions intact.

    Params:
        path:  The path whose permissions to alter.
    """
    NO_USER_WRITING = ~stat.S_IWUSR
    NO_GROUP_WRITING = ~stat.S_IWGRP
    NO_OTHER_WRITING = ~stat.S_IWOTH
    NO_WRITING = NO_USER_WRITING & NO_GROUP_WRITING & NO_OTHER_WRITING

    current_permissions = stat.S_IMODE(os.lstat(path).st_mode)
    os.chmod(path, current_permissions & NO_WRITING)

为什么这个能够工作?

正如John La Rooy所指出的stat.S_IWUSR基本上意味着“用户写权限的掩码”。我们想要将相应的权限位设置为0。为了做到这一点,我们需要一个恰好相反的掩码(即在该位置上有0,在其他所有位置上都有1)。取反运算符~可以完全实现这一点。如果我们通过"位与"运算符(&)将其应用于任何变量,它将清空相应的位。

我们还需要对“组”和“其他”权限位重复此逻辑。在这里,我们可以通过将它们全部&在一起(形成NO_WRITING位常量)来节省一些时间。

最后一步是获取当前文件的权限并执行按位与操作。


似乎有更简洁的方法来完成这个任务。 - Catskul

12

只需在权限数字前添加0:
例如 - 我们想要授予所有权限 - 777
语法:os.chmod("文件名",权限)

import os
os.chmod("file_name" , 0777)

Python 3.7不支持此语法。八进制字面量需要添加 '0o' 前缀 - 这是我在PyCharm中得到的注释。

因此,对于Python 3.7及以上版本,应该这样写:

import os
os.chmod("file_name" , 0o777)

6

以下是一个将9个字符的权限字符串(例如'rwsr-x-wt')转换为与os.chmod()一起使用的掩码的函数。

def perm2mask(p):
        
    assert len(p) == 9, 'Bad permission length'
    assert all(p[k] in 'rw-' for k in [0,1,3,4,6,7]), 'Bad permission format (read-write)'
    assert all(p[k] in 'xs-' for k in [2,5]), 'Bad permission format (execute)'
    assert p[8] in 'xt-', 'Bad permission format (execute other)'
    
    m = 0
    
    if p[0] == 'r': m |= stat.S_IRUSR 
    if p[1] == 'w': m |= stat.S_IWUSR 
    if p[2] == 'x': m |= stat.S_IXUSR 
    if p[2] == 's': m |= stat.S_IXUSR | stat.S_ISUID 
    
    if p[3] == 'r': m |= stat.S_IRGRP 
    if p[4] == 'w': m |= stat.S_IWGRP 
    if p[5] == 'x': m |= stat.S_IXGRP 
    if p[5] == 's': m |= stat.S_IXGRP | stat.S_ISGID 
    
    if p[6] == 'r': m |= stat.S_IROTH 
    if p[7] == 'w': m |= stat.S_IWOTH 
    if p[8] == 'x': m |= stat.S_IXOTH 
    if p[8] == 't': m |= stat.S_IXOTH | stat.S_ISVTX
    
    return m

注意,设置 SUID/SGID/SVTX 位会自动设置相应的执行位。如果没有这样做,将导致权限无效(ST 字符)。

4
你也可以使用pathlib。
from pathlib import Path

fl = Path("file_name")

fl.chmod(0o444)

3

在Python 3.4+中,当使用pathlib.Path对象时,您可以直接将chmod()作为路径对象上的方法调用。以下示例在文档中给出:

>>> p = Path('setup.py')
>>> p.stat().st_mode
33277
>>> p.chmod(0o444)
>>> p.stat().st_mode
33060

-1

不需要记住标志。请记住您可以随时执行以下操作:

subprocess.call(["chmod", "a-w", "file/path])

虽然不可移植,但易于编写和记忆:

  • u - 用户
  • g - 组
  • o - 其他人
  • a - 所有人
  • + 或 - (添加或删除权限)
  • r - 读取
  • w - 写入
  • x - 执行

有关其他选项和更详细的说明,请参阅man chmod


6
这种方法的关键问题在于它假设它正在Unix-like系统上运行。这不是可移植的,因为它在Windows上无法运行。你应该使用os.chmod,就像Gitano的答案中建议的那样。 - code_dredd

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接