Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you do a simple "chmod +x" from within python?

Tags:

python

chmod

People also ask

How do you use chmod +x?

In short, chmod +x following by a filename, usually a script, means that you make it executable. In Ubuntu or other distro that uses GNOME, you can achieve the same result by right click on your file/script and choose Properties, then switch to Permissions tab, tick the Allow executing file as program checkbox.

What is chmod a X?

chmod a+x will add the exec bits to the file but will not touch other bits. For example file might be still unreadable to others and group . chmod 755 will always make the file with perms 755 no matter what initial permissions were. This may or may not matter for your script. Follow this answer to receive notifications.


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/sh\n')
    f.write('echo "hello world"\n')

make_executable(path)

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


If you're using Python 3.4+, you can use the standard library's convenient pathlib.

Its Path class has built-in chmod and stat methods.

from pathlib import Path
import stat


f = Path("/path/to/file.txt")
f.chmod(f.stat().st_mode | stat.S_IEXEC)

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.


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.