Programování

Automatizace v Pythonu: třídění souborů, zálohy a spouštění cronem

Python skripty pro úklid složky se staženými soubory, rotaci záloh a hromadné přejmenování – a jejich spouštění přes cron nebo systemd timer.

12. 10. 2026 · 4 min čtení

Opakující se práci se soubory je škoda dělat ručně. V tomto článku napíšeme tři užitečné skripty pomocí pathlib a shutil a ukážeme, jak je spolehlivě spouštět automaticky – včetně chyb, na které cron rád upozorní až po týdnu.

Základ: pathlib místo os.path

from pathlib import Path

slozka = Path.home() / "Stažené"
for soubor in slozka.iterdir():
    if soubor.is_file():
        print(soubor.name, soubor.suffix, soubor.stat().st_size)

list(slozka.glob("*.pdf"))        # PDF v této složce
list(slozka.rglob("*.jpg"))       # JPG rekurzivně

Operátor / skládá cesty bez starostí o lomítka a funguje stejně na Linuxu i Windows.

Skript 1: třídění složky podle přípony

#!/usr/bin/env python3
import shutil
from pathlib import Path

ZDROJ = Path.home() / "Stažené"
PRAVIDLA = {
    "Dokumenty": {".pdf", ".docx", ".xlsx", ".odt", ".txt"},
    "Obrázky": {".jpg", ".jpeg", ".png", ".gif", ".webp"},
    "Archivy": {".zip", ".tar", ".gz", ".7z"},
    "Instalátory": {".deb", ".exe", ".msi", ".dmg"},
}

def cil_pro(pripona: str) -> str | None:
    for slozka, pripony in PRAVIDLA.items():
        if pripona.lower() in pripony:
            return slozka
    return None

def volne_jmeno(cesta: Path) -> Path:
    """Když soubor existuje, přidá (1), (2)…"""
    if not cesta.exists():
        return cesta
    i = 1
    while True:
        kandidat = cesta.with_name(f"{cesta.stem} ({i}){cesta.suffix}")
        if not kandidat.exists():
            return kandidat
        i += 1

for soubor in ZDROJ.iterdir():
    if not soubor.is_file():
        continue
    slozka = cil_pro(soubor.suffix)
    if slozka is None:
        continue
    cil = ZDROJ / slozka
    cil.mkdir(exist_ok=True)
    shutil.move(soubor, volne_jmeno(cil / soubor.name))
    print(f"{soubor.name} → {slozka}/")

Funkce volne_jmeno řeší nejčastější problém: přesun by jinak tiše přepsal stejnojmenný soubor.

Skript 2: záloha s rotací

Zabalí adresář do .tar.gz s datem v názvu a ponechá posledních N záloh:

#!/usr/bin/env python3
import shutil
from datetime import datetime
from pathlib import Path

ZDROJ = Path("/var/www/muj-web")
CIL = Path("/var/backups/muj-web")
PONECHAT = 7

CIL.mkdir(parents=True, exist_ok=True)
nazev = CIL / f"web-{datetime.now():%Y-%m-%d_%H%M}"
archiv = shutil.make_archive(str(nazev), "gztar", root_dir=ZDROJ)
print("Vytvořeno:", archiv)

zalohy = sorted(CIL.glob("web-*.tar.gz"))
for stara in zalohy[:-PONECHAT]:
    stara.unlink()
    print("Smazáno:", stara.name)

Řazení podle jména funguje díky formátu data RRRR-MM-DD. Proto datum v názvech souborů vždy pište takto.

Skript 3: hromadné přejmenování s náhledem

#!/usr/bin/env python3
import re
import sys
from pathlib import Path

slozka = Path(sys.argv[1])
provest = "--ok" in sys.argv

for i, f in enumerate(sorted(slozka.glob("*.jpg")), start=1):
    nove = f.with_name(f"dovolena-{i:03d}{f.suffix.lower()}")
    print(f"{f.name} → {nove.name}")
    if provest:
        f.rename(nove)

if not provest:
    print("\nNanečisto. Spusťte s --ok pro provedení.")

Režim „nanečisto“ je u destruktivních skriptů zlaté pravidlo.

Spouštění přes cron

Skript udělejte spustitelný a otevřete crontab:

chmod +x ~/skripty/zaloha.py
crontab -e
# min hod den měs dvt  příkaz
30 2 * * * /usr/bin/python3 /home/jan/skripty/zaloha.py >> /home/jan/logs/zaloha.log 2>&1
*/15 * * * * /home/jan/projekt/.venv/bin/python /home/jan/projekt/uklid.py

Proč skript v cronu nefunguje, i když ručně ano

  1. Jiné prostředí. Cron má minimální PATH a neaktivuje virtuální prostředí. Volejte přímo interpret z venv: /cesta/.venv/bin/python.
  2. Relativní cesty. Pracovní adresář je domovská složka, ne složka skriptu. V kódu používejte Path(__file__).resolve().parent.
  3. Výstup mizí. Bez přesměrování >> log 2>&1 cron výstup posílá e-mailem (pokud je nastaven) nebo zahodí. Chybu pak nikdy neuvidíte.
  4. Znak % má v crontabu zvláštní význam (nový řádek) a musí se escapovat \%. Datum generujte raději v Pythonu.

Ověření, že cron úlohu spustil:

grep CRON /var/log/syslog      # Debian/Ubuntu
journalctl -u cron --since today

Alternativa: systemd timer

Na serveru se systemd je timer často lepší volba: logy jdou do journalu, úloha se dá spustit ručně a s Persistent=true se dožene, pokud byl počítač v daný čas vypnutý.

/etc/systemd/system/zaloha.service:

[Unit]
Description=Záloha webu

[Service]
Type=oneshot
User=jan
ExecStart=/usr/bin/python3 /home/jan/skripty/zaloha.py

/etc/systemd/system/zaloha.timer:

[Unit]
Description=Denní záloha webu

[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true

[Install]
WantedBy=timers.target
sudo systemctl daemon-reload
sudo systemctl enable --now zaloha.timer
systemctl list-timers
sudo systemctl start zaloha.service   # ruční spuštění pro test
journalctl -u zaloha.service -n 50

Pojistky pro automatické skripty

  • Před mazáním vždy logujte, co se maže.
  • Ošetřete souběh: když předchozí běh ještě neskončil, nový by neměl začít. V cronu pomůže flock -n /tmp/zaloha.lock python3 zaloha.py.
  • Zálohy občas zkuste obnovit. Záloha, kterou nikdo nezkoušel rozbalit, je jen naděje.

Pokud máte VPS připojený k ColdHost AI, můžete v režimu Server a DevOps nechat AI timer vytvořit – navržené příkazy uvidíte a každý schválíte, než se spustí.