Python equivalent of Perl file test readable (-r), writeable (-w) and executable (-x) operators
I have been Googling to try and find an equival开发者_如何学运维ent in Python to some of Perl's file test operators.
Most of the file test operators are just a direct Pythonification of the underlying os' stat
call. For example, os.stat('file').st_ctime
just reads the inode change time as the *nix stat
utility or ls -l
would do.
Some of the Perl file test operators I cannot find an equivalent in Python. For example, I have a data tree of 85,000 image files created by a variety of applications. Some of the files have the effective UID set in a way that is nettlesome and a modification fails for a permission issue. So for those files I need to run something like:
$ find . -type f -print0 | perl -0 -lnE 'say unless -w' | change euid...
Since I have not found the equivalent in Python, I have to shell out to Perl to find these files. I found this table which suggests there is no direct equivalent. True?
Looking at the output of strace
, perl does a stat()
call followed by getgroups()
to get the supplementary group IDs of the perl process. So it seems it just checks the results of the stat()
call against the EUID, EGID and supplementary group IDs.
Python has a getgroups()
function in os
, so I'm sure you could do the same.
EDIT: You could try something like this if nobody comes up with a better answer. (Hardly tested):
def effectively_readable(path):
import os, stat
uid = os.getuid()
euid = os.geteuid()
gid = os.getgid()
egid = os.getegid()
# This is probably true most of the time, so just let os.access()
# handle it. Avoids potential bugs in the rest of this function.
if uid == euid and gid == egid:
return os.access(path, os.R_OK)
st = os.stat(path)
# This may be wrong depending on the semantics of your OS.
# i.e. if the file is -------r--, does the owner have access or not?
if st.st_uid == euid:
return st.st_mode & stat.S_IRUSR != 0
# See comment for UID check above.
groups = os.getgroups()
if st.st_gid == egid or st.st_gid in groups:
return st.st_mode & stat.S_IRGRP != 0
return st.st_mode & stat.S_IROTH != 0
Obviously the -w one would be almost identical, but with W_OK, S_IWUSR, etc.
Starting with Python 3.3 you can do this with os.access
:
Changed in version 3.3: Added the dir_fd, effective_ids, and follow_symlinks parameters.
If effective_ids is True, access() will perform its access checks using the effective uid/gid instead of the real uid/gid. effective_ids may not be supported on your platform; you can check whether or not it is available using os.supports_effective_ids. If it is unavailable, using it will raise a NotImplementedError.
To check if your effective user can write to a file, most would simply open it and try, and catch the error in an exception. May not be the correct solution in all cases, but goes some way to explaining why there is no specific support for this.
os.access
does exactly what you want.
Use the real uid/gid to test for access to path. Note that most operations will use the effective uid/gid, therefore this routine can be used in a suid/sgid environment to test if the invoking user has the specified access to path.
精彩评论