Python 模块 os.chmod (文件,664)不会更改对 rw-rw-r ——但是-w —— wx ——的权限

最近我在使用 Python 模块 os,当我试图更改一个文件的权限时,我没有得到预期的结果。例如,我打算将权限更改为 rw-rw-r —— ,

os.chmod("/tmp/test_file", 664)

所有权权限实际上是-w —— wx ——-(230)

--w--wx--- 1 ag ag 0 Mar 25 05:45 test_file

但是,如果我在代码中将664改为0664,结果正是我所需要的,例如。

os.chmod("/tmp/test_file", 0664)

结果是:

-rw-rw-r-- 1 ag ag 0 Mar 25 05:55 test_file

有人能解释一下为什么前导0对于得到正确的结果如此重要吗?

218063 次浏览

不同的论坛上发现了这个

如果你想知道为什么前零很重要,那是因为 权限被设置为一个八进制整数,Python 自动 将任何前导零的整数视为八进制数, (十进制)也会得到同样的结果。

你正在做的是传递 664,它在八进制是 1230

对你来说,你需要

os.chmod("/tmp/test_file", 436)

[更新]注意,对于 Python3,前缀为0o (zero oh) . E.G,0o666

领先的 0意味着这是 八进制常量,而不是十进制。你需要一个八进制改变文件模式。

权限是一个位掩码,例如,rwxrwx---是二进制的 111111000,很容易将位按3分组,然后转换成八进制,而不是计算小数。

0644(八进制)是二进制的 0.110.100.100(为了便于阅读,我加了点) ,或者,如你所计算的,十进制的 420

因此,对于那些希望语义类似于:

$ chmod 755 somefile

用途:

$ python -c "import os; os.chmod('somefile', 0o755)"

如果你的 Python 年龄超过2.6:

$ python -c "import os; os.chmod('somefile', 0755)"

使用权限符号(stat.S_I*)代替原始八进制数

如果您使用的是更具语义名称的权限符号而不是原始的魔术数字,那么您的问题就可以避免,例如对于 664:

#!/usr/bin/env python3


import os
import stat


os.chmod(
'myfile',
stat.S_IRUSR |
stat.S_IWUSR |
stat.S_IRGRP |
stat.S_IWGRP |
stat.S_IROTH
)

这一点在 https://docs.python.org/3/library/os.html#os.chmod中有记录,其名称与 POSIX C API相同,也出现在 man 2 statman 2 chmod中:

S_IRUSR  (00400)  read by owner
S_IWUSR  (00200)  write by owner
S_IXUSR  (00100)  execute/search by owner
S_IRGRP  (00040)  read by group
S_IWGRP  (00020)  write by group
S_IXGRP  (00010)  execute/search by group
S_IROTH  (00004)  read by others
S_IWOTH  (00002)  write by others
S_IXOTH  (00001)  execute/search by others

另一个优点是文档中提到的更大的可移植性:

注意: 虽然 Windows 支持 chmod(),但是您只能使用它设置文件的只读标志(通过 stat.S_IWRITEstat.S_IREAD常量或相应的整数值)。所有其他位被忽略。

chmod +x在: 如何在 python 内部执行一个简单的“ chmod + x”?演示

在 Ubuntu 16.04,Python 3.5.2中测试。

如果您希望保存到字符串的权限,请执行

s = '660'
os.chmod(file_path, int(s, base=8))

用统计数据。* 在我看来,位掩码确实是最便携、最明确的方法。但另一方面,我经常忘记如何最好地处理这个问题。因此,这里有一个屏蔽“组”和“其他”权限并保留“所有者”权限不变的示例。使用位掩码和减法是一种有用的模式。

import os
import stat
def chmodme(pn):
"""Removes 'group' and 'other' perms. Doesn't touch 'owner' perms."""
mode = os.stat(pn).st_mode
mode -= (mode & (stat.S_IRWXG | stat.S_IRWXO))
os.chmod(pn, mode)

@ mc.Dev 的回答是这里的最佳答案,我最终利用它来制作下面的函数包装器以供重用。谢谢你的分享。

def chmod_digit(file_path, perms):
"""
Helper function to chmod like you would in unix without having to preface 0o or converting to octal yourself.
Credits: https://stackoverflow.com/a/60052847/1621381
"""
os.chmod(file_path, int(str(perms), base=8))