¿Cómo se hace un simple "chmod + x" desde dentro de Python?

119

Quiero crear un archivo desde un script de Python que sea ejecutable.

import os
import stat
os.chmod('somefile', stat.S_IEXEC)

parece os.chmodque no 'agrega' permisos como lo chmodhace Unix . Con la última línea comentada, el archivo tiene el -rw-r--r--modo de archivo, sin comentar, el modo de archivo es ---x------. ¿Cómo puedo simplemente agregar la u+xbandera manteniendo intactos el resto de los modos?

sacerdotec
fuente

Respuestas:

197

Úselo os.stat()para obtener los permisos actuales, use |to o los bits juntos y useos.chmod() para establecer los permisos actualizados.

Ejemplo:

import os
import stat

st = os.stat('somefile')
os.chmod('somefile', st.st_mode | stat.S_IEXEC)
Ignacio Vázquez-Abrams
fuente
2
Esto solo lo hace ejecutable por el usuario. El cartel preguntaba sobre "chmod + x", lo que lo hace ejecutable en todos los ámbitos (usuario, grupo, mundo)
eric.frederich
35
Utilice lo siguiente para que todos puedan ejecutarlo ... stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH. Nota: ese valor es el mismo que el octal 0111, por lo que podría simplemente hacer st.st_mode | 0111
eric.frederich
1
Mi respuesta a continuación copia los bits R a X, como cabría esperar de, por ejemplo, un compilador.
Jonathon Reinhart
Lo haría STAT_OWNER_EXECUTABLE = stat.S_IEXEC, y usaría la constante local legible por humanos en lugar del galimatías.
ThorSummoner
aquí hay una respuesta no pitónica que puede ser un poco más legible: subprocess.check_call(['chmod', '+x', 'somefile'])y le permite realizar operaciones como a+rx.
Trevor Boyd Smith
20

Para las herramientas que generan archivos ejecutables (por ejemplo, scripts), el siguiente código puede ser útil:

def make_executable(path):
    mode = os.stat(path).st_mode
    mode |= (mode & 0o444) >> 2    # copy R bits to X
    os.chmod(path, mode)

Esto hace que se respete (más o menos) lo umaskque estaba en vigor cuando se creó el archivo: Ejecutable solo está configurado para aquellos que pueden leer.

Uso:

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)
Jonathon Reinhart
fuente
2
Los literales octales cambiaron en Python 3. En lugar de 0444, usarías 0o444. O, si desea apoyar a ambos, simplemente escriba 292.
Kevin
1
@Kevin Parece que la nueva sintaxis ha sido compatible con Python 2.6, por lo que parece razonable usarla. (Para un punto de referencia de compatibilidad, CentOS 6 se envía con Python 2.6).
Jonathon Reinhart
2
No sabía que Python 3 había eliminado los literales octales tradicionales. Así que gracias por eso.
Jonathon Reinhart
13

Si conoce los permisos que desea, el siguiente ejemplo puede ser la forma de simplificarlo.

Python 2:

os.chmod("/somedir/somefile", 0775)

Python 3:

os.chmod("/somedir/somefile", 0o775)

Compatible con (conversión octal):

os.chmod("/somedir/somefile", 509)

ejemplos de permisos de referencia

zerocog
fuente
4
Esto debería ser os.chmod ("/ somedir / somefile", 0o775)
ang mo
4

También puedes hacer esto

>>> import os
>>> st = os.stat("hello.txt")

Listado actual del archivo

$ ls -l hello.txt
-rw-r--r--  1 morrison  staff  17 Jan 13  2014 hello.txt

Ahora hacer esto.

>>> os.chmod("hello.txt", st.st_mode | 0o111)

y verá esto en la terminal.

ls -l hello.txt    
-rwxr-xr-x  1 morrison  staff  17 Jan 13  2014 hello.txt

Puede bit a bit o con 0o111 para hacer todo ejecutable, 0o222 para hacer que todo se pueda escribir y 0o444 para hacer que todo sea legible.

ncmathsadist
fuente
2

Respeto umaskcomochmod +x

man chmoddice que si augono se da como en:

chmod +x mypath

luego ase usa pero con umask:

Una combinación de las letras ugoa controla qué usuarios cambiarán el acceso al archivo: el usuario que lo posee (u), otros usuarios en el grupo del archivo (g), otros usuarios que no están en el grupo del archivo (o), o todos usuarios (a). Si no se da ninguno de estos, el efecto es como si se diera (a), pero los bits que se establecen en la umask no se ven afectados.

Aquí hay una versión que simula ese comportamiento exactamente:

#!/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')

Consulte también: ¿Cómo puedo obtener los permisos de archivo predeterminados en Python?

Probado en Ubuntu 16.04, Python 3.5.2.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
fuente
1

En python3:

import os
os.chmod("somefile", 0o664)

Recuerde agregar el 0oprefijo ya que los permisos se establecen como un entero octal y Python trata automáticamente cualquier entero con un cero a la izquierda como octal. De lo contrario, está pasando de os.chmod("somefile", 1230)hecho, que es octal de 664.

funkid
fuente
1
Esto establece los permisos en un valor absoluto, no lo hace chmod +como lo solicita OP, que debería agregar nuevos permisos a los existentes.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
0

Si está usando Python 3.4+, puede usar el conveniente pathlib de la biblioteca estándar .

Su clase Path tiene métodos chmod y stat integrados .

from pathlib import Path


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