What is the Python way for recursively setting file permissions?
What's the "python way" to recursively set the owner and group to files in a directory? I could just pass a 'chown -R' command to shell, but I feel like I'm missing something obvious.
I'm mucking about with this:
import os
path = "/tmp/foo"
for root, dirs, files in os.walk(path):
for momo in dirs:
os.chown(momo, 502, 20)
This seems to work for setting the directory, but fails when applied to files. I suspect the files are not getting the whole path, so chown fails s开发者_JS百科ince it can't find the files. The error is:
'OSError: [Errno 2] No such file or directory: 'foo.html'
What am I overlooking here?
The dirs
and files
lists are all always relative to root
- i.e., they are the basename()
of the files/folders, i.e. they don't have a /
in them (or \
on windows). You need to join the dirs/files to root
to get their whole path if you want your code to work to infinite levels of recursion:
import os
path = "/tmp/foo"
for root, dirs, files in os.walk(path):
for momo in dirs:
os.chown(os.path.join(root, momo), 502, 20)
for momo in files:
os.chown(os.path.join(root, momo), 502, 20)
I'm suprised the shutil
module doesn't have a function for this.
As correctly pointed out above, the accepted answer misses top-level files and directories. The other answers use os.walk
then loop through dirnames
and filenames
. However, os.walk
goes through dirnames
anyway, so you can skip looping through dirnames
and just chown
the current directory (dirpath
):
def recursive_chown(path, owner):
for dirpath, dirnames, filenames in os.walk(path):
shutil.chown(dirpath, owner)
for filename in filenames:
shutil.chown(os.path.join(dirpath, filename), owner)
I could just pass a 'chown -R' command to shell
This is the simplest way, and gets lost in the question a bit, so just for clarity, you can do this in one line if you don't care about Windows:
os.system('chown -R 502 /tmp/foo')
import os
path = "/tmp/foo"
for root, dirs, files in os.walk(path):
for momo in dirs:
os.chown(momo, 502, 20)
for file in files:
fname = os.path.join(root, file)
os.chown(fname, aaa, bb)
substitute aaa
and bb
as you please
try os.path.join(root,momo)
that will give you full path
Here is a function i wrote that uses glob to recursively list files and change their permissions.
import os
import glob
def recursive_file_permissions(path,mode,uid=-1,gid=-1):
'''
Recursively updates file permissions on a given path.
UID and GID default to -1, and mode is required
'''
for item in glob.glob(path+'/*'):
if os.path.isdir(item):
recursive_file_permissions(os.path.join(path,item),mode,uid,gid)
else:
try:
os.chown(os.path.join(path,item),uid,gid)
os.chmod(os.path.join(path,item),mode)
except:
print('File permissions on {0} not updated due to error.'.format(os.path.join(path,item)))
it's not perfect, but got me where I needed to be
The accepted answer misses top level files. This is the actual equivalent of chown -R
.
import os
path = "/tmp/foo"
os.chown(path, 502, 20)
for dirpath, dirnames, filenames in os.walk(path):
for dname in dirnames:
os.chown(os.path.join(dirpath, dname), 502, 20)
for fname in filenames:
os.chown(os.path.join(dirpath, fname), 502, 20)
Don't forget the for f in files
loop, either. Similarly, remember to os.path.join(root, f)
to get the full path.
"""
Requires python 3
Accepts name or id
Usage:
chown.py -p /temp/folder -u user -g group -r true
or
chown.py -p /temp/folder -u uid -g gid -r 1
user, group, and recursive are optional
But must supply at least one of user or group
Example: sudo chown.py -p /temp/filename -u some_user
"""
import argparse, os, sys
from shutil import chown
user = group = recursive = ''
parser=argparse.ArgumentParser()
parser.add_argument('-p', '--path') # help='file/path'
parser.add_argument('-u', '--user') # , help='user'
parser.add_argument( '-g','--group') # , help='group'
parser.add_argument('-r', '--recursive', help=1) # , help='recursive'
args=parser.parse_args()
path = args.path
if not path:
raise Exception('missing path')
if args.user:
user = args.user
if args.group:
user = args.group
if args.recursive:
recursive = True
if not user and not group:
raise Exception('must supply user, group, or both')
def change_owner(path, user='', group='')
if user and not group:
chown(path, user=user)
elif not user and group:
chown(path, group=group)
else:
chown(path, user, group)
change_owner(path, user, group)
if recursive:
for dirpath, dirnames, filenames in os.walk(path):
for dname in dirnames:
change_owner(os.path.join(dirpath, dname), user, group)
for fname in filenames:
change_owner(os.path.join(dirpath, fname), user, group)
use os.lchown
instead of os.chown
for changing link themselves and files together.
精彩评论