如何从文件中获取Unix权限掩码?

70

我该如何使用Python在*nix系统中获取文件的权限掩码,例如644或755?

是否有相应的函数或类可以实现此功能?非常感谢!

9个回答

124

os.stat 是围绕着系统调用接口 stat(2) 的一个包装器。

>>> import os
>>> from stat import *
>>> os.stat("test.txt") # returns 10-tupel, you really want the 0th element ...
posix.stat_result(st_mode=33188, st_ino=57197013, \
    st_dev=234881026L, st_nlink=1, st_uid=501, st_gid=20, st_size=0, \
    st_atime=1300354697, st_mtime=1300354697, st_ctime=1300354697)

>>> os.stat("test.txt")[ST_MODE] # this is an int, but we like octal ...
33188

>>> oct(os.stat("test.txt")[ST_MODE])
'0100644'

从这里开始,您将认识到典型的八进制权限。

S_IRWXU 00700   mask for file owner permissions
S_IRUSR 00400   owner has read permission
S_IWUSR 00200   owner has write permission
S_IXUSR 00100   owner has execute permission
S_IRWXG 00070   mask for group permissions
S_IRGRP 00040   group has read permission
S_IWGRP 00020   group has write permission
S_IXGRP 00010   group has execute permission
S_IRWXO 00007   mask for permissions for others (not in group)
S_IROTH 00004   others have read permission
S_IWOTH 00002   others have write permission
S_IXOTH 00001   others have execute permission

你只对低位的比特位感兴趣,因此你可以截掉其余的部分:

>>> oct(os.stat("test.txt")[ST_MODE])[-3:]
'644'
>>> # or better
>>> oct(os.stat("test.txt").st_mode & 0o777)
注意:上面的部分确定文件类型,例如:
S_IFMT      0170000 bitmask for the file type bitfields
S_IFSOCK    0140000 socket
S_IFLNK     0120000 symbolic link
S_IFREG     0100000 regular file
S_IFBLK     0060000 block device
S_IFDIR     0040000 directory
S_IFCHR     0020000 character device
S_IFIFO     0010000 FIFO
S_ISUID     0004000 set UID bit
S_ISGID     0002000 set-group-ID bit (see below)
S_ISVTX     0001000 sticky bit (see below)

13
我大部分喜欢这个答案,但是位掩码似乎比字符串切片更干净:oct(os.stat("test.txt").st_mode & 0777) - ncoghlan
oct(os.stat("test.txt")[ST_MODE])[-3:] 在OSX上不起作用。而是使用 oct(os.stat("test.txt")[0])[-3:] 或者 .st_mode & 0777 - J.J
1
@user3329564 对我来说它有效 - ST_MODEstat 模块中,你导入了吗? - Carson Myers
2
os.stat 看起来返回的是一个命名元组,因此您可以使用点符号访问其值。
>> os.stat('.bashrc').st_mode
33188
>> os.stat('.bashrc').st_uid
1000因此无需 import stat
- jerblack

55

我认为这是获取文件权限位最清晰的方法:

stat.S_IMODE(os.lstat("file").st_mode)
如果该文件是符号链接,则使用 os.lstat() 将会给出链接本身的模式,而 os.stat() 将解引用该链接。因此,我认为 os.lstat() 是最常用的。

stat.S_IMODE() 可以获取“文件的权限位,加上粘着位、设置组 ID 位和设置用户 ID 位”。

以下是一个示例情况,给定普通文件 "testfile" 和指向它的符号链接 "testlink:"

import stat
import os

print oct(stat.S_IMODE(os.lstat("testlink").st_mode))
print oct(stat.S_IMODE(os.stat("testlink").st_mode))

这个脚本对我输出以下结果:

0777
0666

3
请注意,在Python 3 中有新的八进制语法,因此上面例子的输出结果为0o7770o666,而不是07770666。请注意,这里只翻译内容,不提供解释或其他信息。 - patryk.beza
由于 stat.S_IMODE() 还包括粘着位、SGID 位和 SUID 位,因此八进制数可能高达 4 位。为了显示方便,最好将它们的位数补齐到 4 位:format(stat.S_IMODE(...), '#06o')(使用 6 而不是 4,因为前缀 0o 也要算在内),这样可以得到 0o07770o0666 - wjandrea

9
如果您不想弄清stat的含义,另一种方法是使用os.access命令。 http://docs.python.org/library/os.html#os.access 但请务必阅读有关可能安全问题的文档。 例如,要检查具有读/写权限的test.dat文件的权限。
os.access("test.dat",os.R_OK)
>>> True

#Execute permissions
os.access("test.dat",os.X_OK)
>>> False

#And Combinations thereof
os.access("test.dat",os.R_OK or os.X_OK)
>>> True

os.access("test.dat",os.R_OK and os.X_OK)
>>> False

2
oct(os.stat('file').st_mode)[4:]

2

os.access(path, mode) 方法会在允许访问路径时返回 True,否则返回 False

可用的模式包括:

  1. os.F_OK - 测试路径是否存在。
  2. os.R_OK - 测试路径是否可读。
  3. os.W_OK - 测试路径是否可写。
  4. os.X_OK - 测试路径是否可执行。

例如,检查文件 /tmp/test.sh 是否具有执行权限:

ls -l /tmp/temp.sh
-rw-r--r--  1 *  *  0 Mar  2 12:05 /tmp/temp.sh

os.access('/tmp/temp.sh',os.X_OK)
False

after changing the file permission to +x 
chmod +x /tmp/temp.sh

ls -l /tmp/temp.sh
-rwxr-xr-x  1 *  *  0 Mar  2 12:05 /tmp/temp.sh

os.access('/tmp/temp.sh',os.X_OK)
True

2
这里有一个简单的方法来检查目录的权限。
import os
import stat

mode = os.stat("path_of_directory").st_mode

if not ((mode & stat.S_IWUSR):
  print('not writable by user')

if not ((mode & stat.S_IWUSR) and (mode & stat.S_IWGRP) and (mode & stat.S_IWOTH)):
  print('not writable by all')

以下是标志列表:
S_IRWXU 00700   mask for file owner permissions
S_IRUSR 00400   owner has read permission
S_IWUSR 00200   owner has write permission
S_IXUSR 00100   owner has execute permission
S_IRWXG 00070   mask for group permissions
S_IRGRP 00040   group has read permission
S_IWGRP 00020   group has write permission
S_IXGRP 00010   group has execute permission
S_IRWXO 00007   mask for permissions for others (not in group)
S_IROTH 00004   others have read permission
S_IWOTH 00002   others have write permission
S_IXOTH 00001   others have execute permission

1

0

os.stat类似于C库的stat函数(在Linux上使用man 2 stat查看信息)

stats = os.stat('file.txt')
print(stats.st_mode)

-2

如果您想要,可以使用Popen运行Bash stat命令:

正常的Bash命令:

jlc@server:~/NetBeansProjects/LineReverse$ stat -c '%A %a %n' revline.c
-rw-rw-r-- 664 revline.c

然后使用Python:

>>> from subprocess import Popen, PIPE
>>> fname = 'revline.c'
>>> cmd = "stat -c '%A %a %n' " + fname
>>> out = Popen(cmd, shell=True, stdout=PIPE).communicate()[0].split()[1].decode()
>>> out
'664'

如果你觉得需要搜索目录,这里还有另一种方法:

>>> from os import popen
>>> cmd = "stat -c '%A %a %n' *"
>>> fname = 'revline.c'
>>> for i in popen(cmd):
...     p, m, n = i.split()
...     if n != fname:
...         continue
...     print(m)
        break
... 
664
>>> 

3
虽然“你可以”这样做是正确的,但除非你编写的是一次性脚本并且完全不关心性能,否则你真的不应该使用这种方法。每次Python程序需要访问文件权限时,这种方法都会创建一个新进程。创建新进程是一个繁重的操作,如果可能的话应该避免。而且由于在这种情况下明显可以避免这种方法,因此这个答案给出了错误的建议。 - silviot

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