pathlib,osvəshutililə faylları və qovluqları təhlükəsiz yaratmaq, köçürmək və kopyalamaqdatetimevətimedeltailə tarixləri formatlamaq, müqayisə etmək və faylların yaşını hesablamaqargparsevəloggingilə peşəkar komanda sətri skripti yazmaq və onu plan üzrə işə salmaq
Leylanın «Yükləmələr» qovluğunda yüzlərlə fayl qarışıq halda durur, hər axşam isə o, sənədlərini əl ilə ehtiyat diskə kopyalayır. Bu, hər gün bir neçə dəqiqə və ara-sıra unudulan ehtiyat nüsxə deməkdir. 25 sətirlik Python skripti faylları saniyələr içində qovluqlara ayırır, sistem planlayıcısı isə onu hər gün özü işə salır. Bu dərsdə belə skriptin bütün hissələrini quracağıq.
Fayllar və qovluqlar: pathlib, os, shutil
| Tapşırıq | Kod |
|---|---|
| qovluğun məzmunu / alt qovluqlarla birlikdə | Path.iterdir(), Path.rglob('*.pdf'), os.walk() |
| qovluq yaratmaq | Path.mkdir(parents=True, exist_ok=True) |
| faylı / qovluğu kopyalamaq | shutil.copy2(src, dst), shutil.copytree(src, dst) |
| köçürmək və ya adını dəyişmək | shutil.move(src, dst), Path.rename(new) |
| faylı / bütün qovluğu silmək | Path.unlink(), shutil.rmtree(path) |
Aşağıdakı skript faylları uzantısına görə qovluqlara ayırır. Real fayllarına toxunmamaq üçün tempfile.mkdtemp() ilə müvəqqəti qovluq yaradırıq və sonda onu silirik. Diqqət et: .JPG və .jpg eyni sayılır, çünki uzantını lower() ilə kiçik hərflərə çeviririk.
import shutil
import tempfile
from pathlib import Path
root = Path(tempfile.mkdtemp())
for name in ['report.pdf', 'photo1.jpg', 'photo2.JPG', 'notes.txt', 'data.csv', 'song.mp3']:
(root / name).write_text('demo')
folders = {'.pdf': 'documents', '.txt': 'documents', '.jpg': 'images', '.csv': 'data'}
for file in list(root.iterdir()):
if file.is_file():
target = root / folders.get(file.suffix.lower(), 'other')
target.mkdir(exist_ok=True)
shutil.move(file, target / file.name)
for path in sorted(root.rglob('*')):
print(path.relative_to(root).as_posix())
shutil.rmtree(root)
print(root.exists())▸ Gözlənilən nəticə
data data/data.csv documents documents/notes.txt documents/report.pdf images images/photo1.jpg images/photo2.JPG other other/song.mp3 False
list(root.iterdir()) siyahını əvvəlcədən götürür — qovluğu dövr zamanı dəyişmək təhlükəsiz olsun deyə. Tanınmayan uzantılar other qovluğuna düşür.Tarix və vaxt
datetime modulunda date, datetime və müddəti ifadə edən timedelta var. strftime tarixi formatlı mətnə çevirir (%Y il, %m ay, %d gün, %H:%M saat), strptime isə əksinə, mətni tarixə. Nəticələr təkrarlana bilsin deyə nümunələrdə datetime.now() əvəzinə sabit tarix götürürük.
from datetime import date, datetime, timedelta
now = datetime(2026, 9, 27, 14, 30)
print(now.strftime('%Y-%m-%d_%H-%M'))
print(now.strftime('%d.%m.%Y'))
deadline = now + timedelta(days=10, hours=3)
print(deadline.isoformat(sep=' '))
print((date(2026, 12, 31) - now.date()).days, 'days left in the year')
parsed = datetime.strptime('05.10.2026 09:15', '%d.%m.%Y %H:%M')
print(parsed, parsed.strftime('%A'))▸ Gözlənilən nəticə
2026-09-27_14-30 27.09.2026 2026-10-07 17:30:00 95 days left in the year 2026-10-05 09:15:00 Monday
Faylın son dəyişmə vaxtını stat().st_mtime verir (1970-ci ildən bəri saniyələr). Onu datetime.fromtimestamp ilə tarixə çevirib limitlə müqayisə edirik. Nümunədə faylların «yaşını» os.utime ilə süni olaraq təyin edirik:
import os
import tempfile
from datetime import datetime, timedelta
from pathlib import Path
root = Path(tempfile.mkdtemp())
now = datetime(2026, 9, 27, 12, 0)
for name, days in {'backup_old.zip': 45, 'log_week.txt': 7, 'log_today.txt': 0}.items():
f = root / name
f.write_text('x')
t = (now - timedelta(days=days)).timestamp()
os.utime(f, (t, t))
limit = now - timedelta(days=30)
for f in sorted(root.iterdir()):
modified = datetime.fromtimestamp(f.stat().st_mtime)
status = 'OLD' if modified < limit else 'ok'
print(f'{f.name:15} {modified:%Y-%m-%d} {status}')▸ Gözlənilən nəticə
backup_old.zip 2026-08-13 OLD log_today.txt 2026-09-27 ok log_week.txt 2026-09-20 ok
argparse və logging
Yaxşı skriptin daxilində yollar və rəqəmlər yazılmır — onları komanda sətrindən alır: python cleanup.py downloads --days 14 --dry-run. argparse mövqe arqumentlərini (folder), seçimləri (--days), bayraqları (--dry-run) təhlil edir, tipləri çevirir və --help səhifəsini özü yaradır. Real skriptdə parse_args() arqumentsiz çağırılır; burada komanda sətrini siyahı ilə imitasiya edirik.
import argparse
parser = argparse.ArgumentParser(prog='cleanup', description='List or delete old files.')
parser.add_argument('folder', help='folder to scan')
parser.add_argument('--days', type=int, default=30, help='age limit in days')
parser.add_argument('--dry-run', action='store_true', help='only show what would happen')
args = parser.parse_args(['downloads', '--days', '14', '--dry-run'])
print(args)
print(args.folder, args.days, args.dry_run)
print(parser.parse_args(['photos']))▸ Gözlənilən nəticə
Namespace(folder='downloads', days=14, dry_run=True) downloads 14 True Namespace(folder='photos', days=30, dry_run=False)
--dry-run atributda dry_run olur (defis alt xəttə çevrilir). İkinci çağırışda göstərilməyən seçimlər susmaya görə qiymətlərini alıb.Plan üzrə işləyən skriptin ekranına heç kim baxmır, ona görə print əvəzinə logging işlədilir: hər mesajın səviyyəsi (DEBUG, INFO, WARNING, ERROR, CRITICAL) və vaxtı olur, onları fayla yazmaq və əhəmiyyətsizləri süzmək olar. %s, %d yer tutucuları mesajı yalnız həqiqətən çap olunanda formatlayır.
import logging
import sys
logging.basicConfig(stream=sys.stdout, level=logging.INFO,
format='%(levelname)-8s %(name)s: %(message)s', force=True)
log = logging.getLogger('backup')
log.debug('not shown: the level is INFO')
log.info('Backup started')
log.warning('Disk is 85% full')
try:
ratio = 10 / 0
except ZeroDivisionError:
log.error('Could not compute the ratio')
log.info('Copied %d files in %.1f s', 128, 3.42)▸ Gözlənilən nəticə
INFO backup: Backup started WARNING backup: Disk is 85% full ERROR backup: Could not compute the ratio INFO backup: Copied 128 files in 3.4 s
sys.stdout) yazılır; real skriptdə filename='backup.log' və formatda %(asctime)s (vaxt) göstərilir. DEBUG səviyyəli mesaj INFO limitindən aşağı olduğu üçün görünmür.Tam skript və onun planlaşdırılması
import argparse
import logging
import shutil
from datetime import datetime
from pathlib import Path
log = logging.getLogger('backup')
def backup(source, dest_root, dry_run=False):
stamp = datetime.now().strftime('%Y-%m-%d_%H-%M')
target = Path(dest_root) / f'{Path(source).name}_{stamp}'
log.info('Copying %s -> %s (dry run: %s)', source, target, dry_run)
if not dry_run:
shutil.copytree(source, target)
return target
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Back up a folder with a timestamp.')
parser.add_argument('source', help='folder to copy')
parser.add_argument('dest', help='where to put the copy')
parser.add_argument('--dry-run', action='store_true', help='only log, do not copy')
args = parser.parse_args()
logging.basicConfig(filename='backup.log', level=logging.INFO,
format='%(asctime)s %(levelname)s %(message)s')
backup(args.source, args.dest, args.dry_run)backup.py. if __name__ == '__main__': bloku yalnız fayl birbaşa işə salınanda icra olunur — backup funksiyasını başqa skriptlərdə və testlərdə import etmək olar. Öz kompüterində: python backup.py Documents D:/Backup --dry-run, sonra backup.log faylına bax.Skripti müntəzəm işə salmaq üçün əməliyyat sisteminin planlayıcısından istifadə olunur: Linux və macOS-də cron, Windows-da Tapşırıq Planlayıcısı (Task Scheduler, komanda sətrində schtasks). cron sətrində beş sahə var: dəqiqə, saat, ayın günü, ay, həftənin günü; * «istənilən» deməkdir.
| cron ifadəsi | Nə vaxt |
|---|---|
0 21 * * * | hər gün saat 21:00-da |
*/15 * * * * | hər 15 dəqiqədən bir |
0 9 * * 1-5 | iş günləri saat 09:00-da |
0 3 1 * * | hər ayın 1-i saat 03:00-da |
# Linux / macOS: open the table with `crontab -e` and add a line
0 21 * * * /home/leyla/.venv/bin/python /home/leyla/scripts/backup.py /home/leyla/Documents /mnt/backup
# Windows (Command Prompt): the same task every day at 21:00
schtasks /Create /SC DAILY /ST 21:00 /TN "Daily backup" /TR "C:\scripts\.venv\Scripts\python.exe C:\scripts\backup.py C:\Users\Leyla\Documents D:\Backup"schedule da var (pip install schedule), amma onunla skript daim açıq qalmalıdır; sistem planlayıcısı kompüter yenidən başlayandan sonra da işləyir.Fayl adlarını uzantıya görə qruplaşdır: uzantını kiçik hərflərlə götür, uzantısı olmayan fayllar üçün '(none)' işlət. Uzantıları sıralanmış halda, hər birinin yanında sıralanmış fayl siyahısı ilə, ayrı sətirlərdə çap et.
from pathlib import PurePath
files = ['report.PDF', 'photo.jpg', 'notes.txt', 'scan.pdf', 'song.mp3', 'README']
# group by lowercase extension, then print: extension [sorted names]▸ Gözlənilən nəticə
(none) ['README'] .jpg ['photo.jpg'] .mp3 ['song.mp3'] .pdf ['report.PDF', 'scan.pdf'] .txt ['notes.txt']
Bu gün 2026-09-27-dir. 30 gündən köhnə hər fayl üçün adını və neçə gün əvvəl dəyişdirildiyini çap et (lüğətdəki sıra ilə). Sonda ən yeni faylı newest: <ad> şəklində çap et.
from datetime import date
today = date(2026, 9, 27)
files = {'backup.zip': '2026-07-30', 'notes.txt': '2026-09-20',
'photo.jpg': '2026-08-15', 'log.txt': '2026-09-27'}
# print old files with their age in days, then the newest file▸ Gözlənilən nəticə
backup.zip 59 photo.jpg 43 newest: log.txt
Əsas fikirlər
pathlibyollar və fayllar üçün,shutilkopyalama, köçürmə və qovluqları silmək üçündür; silinən fayllar geri qayıtmır.datetime,timedelta,strftimevəstrptime; fayl adlarında tarixiYYYY-MM-DDşəklində yaz.argparsemövqe arqumentləri, seçimlər, bayraqlar və avtomatik--helpverir.- Plan üzrə işləyən skriptlərdə
printyox, səviyyələri və vaxtı olanloggingişlət. - cron və ya Tapşırıq Planlayıcısı skripti müntəzəm işə salır; mütləq yollar, tam
pythonyolu və--dry-runvərdişi.
Özünü yoxla
10 sual. Hər düzgün cavab XP qazandırır.