Como você faz um simples “chmod + x” de dentro do python?

119

Quero criar um arquivo de dentro de um script python que é executável.

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

parece os.chmodque não 'adiciona' permissões como o Unix chmodfaz. Com a última linha comentada, o arquivo tem o modo de arquivo -rw-r--r--, sem comentar, o modo de arquivo é ---x------. Como posso apenas adicionar o u+xsinalizador enquanto mantenho o resto dos modos intactos?

sacerdote
fonte

Respostas:

197

Use os.stat()para obter as permissões atuais, use |para ou os bits juntos e use os.chmod()para definir as permissões atualizadas.

Exemplo:

import os
import stat

st = os.stat('somefile')
os.chmod('somefile', st.st_mode | stat.S_IEXEC)
Ignacio Vazquez-Abrams
fonte
2
Isso apenas o torna executável pelo usuário. O pôster estava perguntando sobre "chmod + x", o que o torna executável em todo o quadro (usuário, grupo, mundo)
eric.frederich
35
Use o seguinte para torná-lo executável por todos ... stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH. Observação: esse valor é igual ao octal 0111, então você poderia apenas fazer st.st_mode | 0111
eric.frederich
1
Minha resposta a seguir copia os bits R para X, como seria de se esperar, um compilador.
Jonathon Reinhart
Eu o faria STAT_OWNER_EXECUTABLE = stat.S_IEXEC, e usaria a constante local legível por humanos em vez do jargão.
ThorSummoner
aqui está uma resposta não pythônica que pode ser um pouco mais legível: subprocess.check_call(['chmod', '+x', 'somefile'])e permite que você faça operações como a+rx.
Trevor Boyd Smith
20

Para ferramentas que geram arquivos executáveis ​​(por exemplo, scripts), o código a seguir pode 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)

Isso faz com que (mais ou menos) respeite o umaskque estava em vigor quando o arquivo foi criado: Executável é definido apenas para aqueles que podem ler.

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
fonte
2
Os literais octais mudaram no Python 3. Em vez de 0444, você usaria 0o444. Ou, se quiser apoiar os dois, basta escrever 292.
Kevin
1
@Kevin Parece que a nova sintaxe foi suportada pelo Python 2.6, então parece razoável usá-la. (Para um ponto de referência de compatibilidade, CentOS 6 vem com Python 2.6).
Jonathon Reinhart
2
Eu não sabia que o Python 3 tinha removido os literais octais tradicionais. Então, obrigado por isso.
Jonathon Reinhart
12

Se você souber as permissões que deseja, o exemplo a seguir pode ser a maneira de mantê-lo simples.

Python 2:

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

Python 3:

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

Compatível com (conversão octal):

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

exemplos de permissões de referência

zerocog
fonte
4
Deve ser os.chmod ("/ somedir / somefile", 0o775)
mês de
4

Você também pode fazer isso

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

Lista atual de arquivo

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

Agora faça isso.

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

e você verá isso no terminal.

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

Você pode bit a bit ou com 0o111 para tornar todos executáveis, 0o222 para tornar todos graváveis ​​e 0o444 para tornar todos legíveis.

ncmathsadist
fonte
2

Respeito umaskcomochmod +x

man chmoddiz que se augonão for fornecido como em:

chmod +x mypath

então aé usado, mas com umask:

Uma combinação das letras ugoa controla quais usuários o acesso ao arquivo será alterado: o usuário que o possui (u), outros usuários no grupo do arquivo (g), outros usuários que não estão no grupo do arquivo (o) ou todos usuários (a). Se nenhum desses for dado, o efeito é como se (a) fosse dado, mas os bits que são configurados no umask não são afetados.

Esta é uma versão que simula exatamente esse comportamento:

#!/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 também: Como posso obter as permissões de arquivo padrão em Python?

Testado no Ubuntu 16.04, Python 3.5.2.

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

Em python3:

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

Lembre-se de adicionar o 0oprefixo, pois as permissões são definidas como um inteiro octal e o Python trata automaticamente qualquer inteiro com um zero à esquerda como octal. Caso contrário, você está os.chmod("somefile", 1230)realmente passando , o que é octal de 664.

funkid
fonte
1
Isso define as permissões com um valor absoluto, não faz um chmod +conforme solicitado pelo OP, que deve adicionar novas permissões às existentes.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
0

Se você estiver usando o Python 3.4+, poderá usar o pathlib conveniente da biblioteca padrão .

Sua classe Path possui métodos internos chmod e stat .

from pathlib import Path


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