Jak wykonać proste „chmod + x” z poziomu Pythona?

119

Chcę utworzyć plik z poziomu skryptu Pythona, który jest wykonywalny.

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

wygląda na to, os.chmodże nie „dodaje” uprawnień tak, jak chmodrobi to unix . Gdy ostatnia linia jest wykomentowana, plik ma kod pliku -rw-r--r--, a nie zakomentowany, tryb pliku to ---x------. Jak mogę po prostu dodać u+xflagę, zachowując pozostałe tryby w stanie nienaruszonym?

ksiądzc
źródło

Odpowiedzi:

197

Użyj, os.stat()aby uzyskać bieżące uprawnienia, użyj |do lub bitów razem i użyj, os.chmod()aby ustawić zaktualizowane uprawnienia.

Przykład:

import os
import stat

st = os.stat('somefile')
os.chmod('somefile', st.st_mode | stat.S_IEXEC)
Ignacio Vazquez-Abrams
źródło
2
To tylko sprawia, że ​​jest on wykonywany przez użytkownika. Plakat pytał o „chmod + x”, co sprawia, że ​​jest on wykonywany na wszystkich platformach (użytkownik, grupa, świat)
eric.frederich
35
Użyj poniższego, aby każdy mógł go uruchomić ... stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH. Uwaga: ta wartość jest taka sama jak ósemkowa 0111, więc możesz po prostu zrobić st.st_mode | 0111
eric.frederich
1
Moja odpowiedź poniżej kopiuje bity R do X, jak można by się spodziewać po kompilatorze.
Jonathon Reinhart
Zrobiłbym i użyłby STAT_OWNER_EXECUTABLE = stat.S_IEXEClokalnej stałej czytelnej dla człowieka zamiast bełkotliwego.
ThorSummoner
oto odpowiedź nie będąca pythonem, która może być trochę bardziej czytelna: subprocess.check_call(['chmod', '+x', 'somefile'])i pozwólmy ci łatwiej wykonywać operacje takie jak a+rx.
Trevor Boyd Smith
20

W przypadku narzędzi generujących pliki wykonywalne (np. Skrypty) pomocny może być następujący kod:

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

To sprawia, że ​​(mniej lub bardziej) respektuje to, umaskco obowiązywało podczas tworzenia pliku: Plik wykonywalny jest ustawiany tylko dla tych, które mogą czytać.

Stosowanie:

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
źródło
2
Literały ósemkowe zostały zmienione w Pythonie 3. Zamiast tego 0444użyłbyś 0o444. Lub, jeśli chcesz wspierać oba, po prostu napisz 292.
Kevin,
1
@Kevin Wygląda na to, że nowa składnia jest obsługiwana przez Python 2.6, więc użycie tego wydaje się rozsądne. (W przypadku punktu odniesienia dotyczącego zgodności CentOS 6 jest dostarczany z Pythonem 2.6).
Jonathon Reinhart
2
Nie wiedziałem, że Python 3 usunął tradycyjne ósemkowe literały. Więc dziękuję za to.
Jonathon Reinhart
13

Jeśli znasz uprawnienia, które chcesz, poniższy przykład może być sposobem na uproszczenie.

Python 2:

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

Python 3:

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

Kompatybilny z (konwersja ósemkowa):

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

przykłady uprawnień referencyjnych

zerocog
źródło
4
Powinien to być os.chmod ("/ somedir / somefile", 0o775)
ang. Mo
4

Ty też możesz to zrobić

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

Bieżąca lista plików

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

Zrób to teraz.

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

i zobaczysz to w terminalu.

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

Możesz ustawić bitowo lub 0o111, aby uczynić wszystko wykonywalnym, 0o222, aby uczynić wszystko zapisywalnym, a 0o444, aby uczynić wszystko czytelnym.

ncmathsadist
źródło
2

Szacunek umaskjakchmod +x

man chmodmówi, że jeśli augonie jest podane jak w:

chmod +x mypath

wtedy ajest używany, ale z umask:

Kombinacja liter ugoa kontroluje dostęp użytkowników do pliku, który zostanie zmieniony: użytkownik będący jego właścicielem (u), inni użytkownicy w grupie pliku (g), inni użytkownicy spoza grupy pliku (o) lub wszyscy użytkowników (a). Jeśli żadna z nich nie zostanie podana, efekt jest taki, jakby podano (a), ale bity ustawione w umask nie ulegają zmianie.

Oto wersja, która dokładnie symuluje takie zachowanie:

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

Zobacz też: Jak mogę uzyskać domyślne uprawnienia do plików w Pythonie?

Testowane w Ubuntu 16.04, Python 3.5.2.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
źródło
1

W python3:

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

Pamiętaj, aby dodać 0oprzedrostek, ponieważ uprawnienia są ustawiane jako ósemkowe liczby całkowite, a Python automatycznie traktuje każdą liczbę całkowitą z wiodącym zerem jako liczbę ósemkową. W przeciwnym razie os.chmod("somefile", 1230)rzeczywiście mijasz, czyli ósemkowo od 664.

ostry
źródło
1
To ustawia uprawnienia na wartość bezwzględną, nie robi tego, o chmod +co prosi OP, który powinien dodać nowe uprawnienia do istniejących.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
0

Jeśli używasz Pythona 3.4+, możesz użyć wygodnej pathlib biblioteki standardowej .

Jego klasa Path ma wbudowane metody chmod i stat .

from pathlib import Path


f = Path("/path/to/file.txt")
f.chmod(f.stat().st_mode | stat.S_IEXEC)
cs01
źródło