How do you do a simple "chmod +x" from within python?
Question:
I want to create a file from within a python script that is executable.
import os
import stat
os.chmod('somefile', stat.S_IEXEC)
it appears os.chmod
doesn’t ‘add’ permissions the way unix chmod
does. With the last line commented out, the file has the filemode -rw-r--r--
, with it not commented out, the file mode is ---x------
. How can I just add the u+x
flag while keeping the rest of the modes intact?
Answers:
Use os.stat()
to get the current permissions, use |
to OR the bits together, and use os.chmod()
to set the updated permissions.
Example:
import os
import stat
st = os.stat('somefile')
os.chmod('somefile', st.st_mode | stat.S_IEXEC)
For tools that generate executable files (e.g. scripts), the following code might be helpful:
def make_executable(path):
mode = os.stat(path).st_mode
mode |= (mode & 0o444) >> 2 # copy R bits to X
os.chmod(path, mode)
This makes it (more or less) respect the umask
that was in effect when the file was created: Executable is only set for those that can read.
Usage:
path = 'foo.sh'
with open(path, 'w') as f: # umask in effect when file is created
f.write('#!/bin/shn')
f.write('echo "hello world"n')
make_executable(path)
You can also do this
>>> import os
>>> st = os.stat("hello.txt")
Current listing of file
$ ls -l hello.txt
-rw-r--r-- 1 morrison staff 17 Jan 13 2014 hello.txt
Now do this.
>>> os.chmod("hello.txt", st.st_mode | 0o111)
and you will see this in the terminal.
ls -l hello.txt
-rwxr-xr-x 1 morrison staff 17 Jan 13 2014 hello.txt
You can bitwise or with 0o111 to make all executable, 0o222 to make all writable, and 0o444 to make all readable.
If you know the permissions you want then the following example may be the way to keep it simple.
Python 2:
os.chmod("/somedir/somefile", 0775)
Python 3:
os.chmod("/somedir/somefile", 0o775)
Compatible with either (octal conversion):
os.chmod("/somedir/somefile", 509)
reference permissions examples
In python3:
import os
os.chmod("somefile", 0o664)
Remember to add the 0o
prefix since permissions are set as an octal integer, and Python automatically treats any integer with a leading zero as octal. Otherwise, you are passing os.chmod("somefile", 1230)
indeed, which is octal of 664
.
Respect umask
like chmod +x
man chmod
says that if augo
is not given as in:
chmod +x mypath
then a
is used but with umask
:
A combination of the letters ugoa controls which users’ access to the file will be changed: the user who owns it (u), other users in the file’s group (g), other users not in the file’s group (o), or all users (a). If none of these are given, the effect is as if (a) were given, but bits that are set in the umask are not affected.
The goal of this is so that you don’t accidentally give too many permissions. umask determines the default permissions of a new file, e.g. with a umask of 0077
, touch newfile.txt
produces permissions rw
for the current user because the 77 would exclude group and other (x is not given by default by touch anyways though). And chmod +x
would similarly only add +x
for user, ignoring group and other due to the 0011
part of the mask: you would need chmod o+x
, chmod g+x
, chmod go+x
or chmod a+x
to force them to be set.
Here is a version that simulates that behavior exactly:
#!/usr/bin/env python3
import os
import stat
def get_umask():
umask = os.umask(0)
os.umask(umask)
return umask
def chmod_plus_x(path):
os.chmod(
path,
os.stat(path).st_mode |
(
(
stat.S_IXUSR |
stat.S_IXGRP |
stat.S_IXOTH
)
& ~get_umask()
)
)
chmod_plus_x('.gitignore')
See also: How can I get the default file permissions in Python?
Tested in Ubuntu 16.04, Python 3.5.2.
we can directly call chmod +x
command in python using os.system()
import os
os.system("chmod +x somefile")
I want to create a file from within a python script that is executable.
import os
import stat
os.chmod('somefile', stat.S_IEXEC)
it appears os.chmod
doesn’t ‘add’ permissions the way unix chmod
does. With the last line commented out, the file has the filemode -rw-r--r--
, with it not commented out, the file mode is ---x------
. How can I just add the u+x
flag while keeping the rest of the modes intact?
Use os.stat()
to get the current permissions, use |
to OR the bits together, and use os.chmod()
to set the updated permissions.
Example:
import os
import stat
st = os.stat('somefile')
os.chmod('somefile', st.st_mode | stat.S_IEXEC)
For tools that generate executable files (e.g. scripts), the following code might be helpful:
def make_executable(path):
mode = os.stat(path).st_mode
mode |= (mode & 0o444) >> 2 # copy R bits to X
os.chmod(path, mode)
This makes it (more or less) respect the umask
that was in effect when the file was created: Executable is only set for those that can read.
Usage:
path = 'foo.sh'
with open(path, 'w') as f: # umask in effect when file is created
f.write('#!/bin/shn')
f.write('echo "hello world"n')
make_executable(path)
You can also do this
>>> import os
>>> st = os.stat("hello.txt")
Current listing of file
$ ls -l hello.txt
-rw-r--r-- 1 morrison staff 17 Jan 13 2014 hello.txt
Now do this.
>>> os.chmod("hello.txt", st.st_mode | 0o111)
and you will see this in the terminal.
ls -l hello.txt
-rwxr-xr-x 1 morrison staff 17 Jan 13 2014 hello.txt
You can bitwise or with 0o111 to make all executable, 0o222 to make all writable, and 0o444 to make all readable.
If you know the permissions you want then the following example may be the way to keep it simple.
Python 2:
os.chmod("/somedir/somefile", 0775)
Python 3:
os.chmod("/somedir/somefile", 0o775)
Compatible with either (octal conversion):
os.chmod("/somedir/somefile", 509)
reference permissions examples
In python3:
import os
os.chmod("somefile", 0o664)
Remember to add the 0o
prefix since permissions are set as an octal integer, and Python automatically treats any integer with a leading zero as octal. Otherwise, you are passing os.chmod("somefile", 1230)
indeed, which is octal of 664
.
Respect umask
like chmod +x
man chmod
says that if augo
is not given as in:
chmod +x mypath
then a
is used but with umask
:
A combination of the letters ugoa controls which users’ access to the file will be changed: the user who owns it (u), other users in the file’s group (g), other users not in the file’s group (o), or all users (a). If none of these are given, the effect is as if (a) were given, but bits that are set in the umask are not affected.
The goal of this is so that you don’t accidentally give too many permissions. umask determines the default permissions of a new file, e.g. with a umask of 0077
, touch newfile.txt
produces permissions rw
for the current user because the 77 would exclude group and other (x is not given by default by touch anyways though). And chmod +x
would similarly only add +x
for user, ignoring group and other due to the 0011
part of the mask: you would need chmod o+x
, chmod g+x
, chmod go+x
or chmod a+x
to force them to be set.
Here is a version that simulates that behavior exactly:
#!/usr/bin/env python3
import os
import stat
def get_umask():
umask = os.umask(0)
os.umask(umask)
return umask
def chmod_plus_x(path):
os.chmod(
path,
os.stat(path).st_mode |
(
(
stat.S_IXUSR |
stat.S_IXGRP |
stat.S_IXOTH
)
& ~get_umask()
)
)
chmod_plus_x('.gitignore')
See also: How can I get the default file permissions in Python?
Tested in Ubuntu 16.04, Python 3.5.2.
we can directly call chmod +x
command in python using os.system()
import os
os.system("chmod +x somefile")