Corrigé du TD 3

Exercice 1

Question 1

On prépare un répertoire de test :

$ mkdir toto
$ cd toto
$ mkdir ga bu zo meu
$ touch 1 2 3 ga/4 bu/5 bu/6 zo/7 meu/8
$ ln -s bu/5 link
In [11]:
ls -R toto
toto:
1  2  3  bu/  ga/  link@  meu/  zo/

toto/bu:
5  6

toto/ga:
4

toto/meu:
8

toto/zo:
7

Question 2

In [12]:
import os
def listfiles(path):
    for root, dirs, files in os.walk(path):
        for f in files: print (os.path.join(root,f))
In [13]:
listfiles('toto')
toto/3
toto/2
toto/link
toto/1
toto/zo/7
toto/meu/8
toto/ga/4
toto/bu/5
toto/bu/6

Question 3

In [14]:
def count1(path):
    f=d=0
    for root, dirs, files in os.walk(path):
        f+=len(files); d+=len(dirs)
    print ("%d files, %d directories" % (f,d))

# ne compte pas "."
In [15]:
count1('toto')
9 files, 4 directories

Question 4

In [16]:
def count2(path):
    f=s=d=0
    for root, dirs, files in os.walk(path):
        for dir_ in dirs:
            if os.path.islink(root+os.sep+dir_): s+=1
            else: d+=1
        for file_ in files:
            if os.path.islink(root+os.sep+file_): s+=1
            else: f+=1

    print ("%d directories, %d files, %d symlinks" % (d,f,s))
In [17]:
count2('toto')
4 directories, 8 files, 1 symlinks

Question 5

In [18]:
# Un lien vers un fichier non existant peut générer une erreur
# On gère avec try/except
def stats(path):
    fpriv=fpub=spriv=spub=dpriv=dpub=0
    for root, dirs, files in os.walk(path):
        for dir_ in dirs:
            try:
                pub = os.stat(root+os.sep+dir_).st_mode % 64
                if os.path.islink(root+os.sep+dir_):
                    if pub: spub+=1
                    else: spriv+=1
                else:
                    if pub: dpub+=1
                    else: dpriv+=1
            except Exception as e :
                print (root+os.sep+dir_+' --> broken link!')
                print (e)
        for file_ in files:
            try:
                pub = os.stat(root+os.sep+file_).st_mode % 64
                if os.path.islink(root+os.sep+file_):
                    if pub: spub+=1
                    else: spriv+=1
                else:
                    if pub: fpub+=1
                    else: fpriv+=1
            except Exception as e:
                print (root+os.sep+file_ + ' --> broken link!')
                print (e)
    print()
    print ("Statistics of %s:" % path)
    print()
    print ("Public directories: %d" % dpub)
    print ("Private directories: %d" % dpriv)
    print ("Public files: %d" % fpub)
    print ("Private files: %d" % fpriv)
    print ("Public symlinks: %d" % spub)
    print ("Private symlinks: %d" % spriv)
In [19]:
stats('toto')
Statistics of toto:

Public directories: 4
Private directories: 0
Public files: 8
Private files: 0
Public symlinks: 1
Private symlinks: 0
In [20]:
ls -lR toto
toto:
total 16
-rw-r--r-- 1 jyt adm    0 oct.   3 13:29 1
-rw-r--r-- 1 jyt adm    0 oct.   3 13:29 2
-rw-r--r-- 1 jyt adm    0 oct.   3 13:29 3
drwxr-xr-x 2 jyt adm 4096 oct.   3 13:29 bu/
drwxr-xr-x 2 jyt adm 4096 oct.   3 13:29 ga/
lrwxrwxrwx 1 jyt adm    4 oct.   3 13:30 link -> bu/5
drwxr-xr-x 2 jyt adm 4096 oct.   3 13:29 meu/
drwxr-xr-x 2 jyt adm 4096 oct.   3 13:29 zo/

toto/bu:
total 0
-rw-r--r-- 1 jyt adm 0 oct.   3 13:29 5
-rw-r--r-- 1 jyt adm 0 oct.   3 13:29 6

toto/ga:
total 0
-rw-r--r-- 1 jyt adm 0 oct.   3 13:29 4

toto/meu:
total 0
-rw-r--r-- 1 jyt adm 0 oct.   3 13:29 8

toto/zo:
total 0
-rw-r--r-- 1 jyt adm 0 oct.   3 13:29 7

Exercice 2

On parcourt récursivement l'arborescence du répertoire examiné, et on calcule un hachage (ici, md5) de chaque fichier rencontré. On utilise ces hachages (des chaines de 32 caractères hexadécimaux, par exemple 643385065da73cee1b42e504b0be1c8d) comme clefs d'un dictionnaire, dont les valeurs sont les listes des fichiers correspondant à ce hachage (donnés avec leur chemin absolu). On renvoie ensuite les listes ayant au moins deux éléments, et on les affiche au format demandé.

#!/usr/bin/env python3
'''
duplicates: lists identical files in a directory.

Usage: duplicates [-e] [--extension] [file extension],
                  [-d] [--directory] [directory]
                  [-o] [--outfile]   [output file]
                  |-h] [--help]
'''

import os, hashlib, sys, getopt


def find_duplicates(extension, directory):
    d = {}
    for root, dirs, files in os.walk(directory):
        for f in files:
            if not extension or os.path.splitext(f)[1][1:] == extension:
                p = os.path.join(root,f)
                try:
                    s = open(p,'rb').read()
                    md5 = hashlib.md5(s).hexdigest()
                    if md5 in d: d[md5].append(p)
                    else: d[md5] = [p]
                except: pass
    return d

def usage():
    'Print usage doc and exit.'
    print (__doc__)
    sys.exit()

if __name__ == '__main__':
    extension = None
    directory = os.getcwd() # portabilité : os.environ['PWD'] n'existe pas sous windows
    outfile = sys.stdout
    out = False

    try:
        optlist, arglist = getopt.getopt(sys.argv[1:],
                                         'he:d:o:',
                                         ['help', 'extension=',
                                          'directory=', 'outfile=' ])
    except:
        usage()
    for option in optlist:
        if option[0] in ['-h', '--help']: usage()
        if option[0] in ['-e', '--extension']: extension = option[1]
        if option[0] in ['-d', '--directory']: directory = option[1]
        if option[0] in ['-o', '--outfile']:
            outfile = open(option[1],'w')
            out = True
    d = find_duplicates(extension, directory)

    for x in d:
        if len(d[x])>1:
            for y in d[x]:
                outfile.write(y+'\n')
            outfile.write('\n')
    if out: outfile.close()

Exercice 3

On construit une expression régulière dist_pat(w) recherchant le remplacement ou effacement de la lettre à chaque position i possible, ou l'insertion d'une lettre avant la position i, en deux étapes.

In [21]:
import re

def dist_pat(w):
    # remplacement ou effacement de la lettre en position i
    ll = [ w[:i] + '.?' + w[i+1:] +'$'  for i in range(len(w))]
    # insertion d'une lettre avant la position i
    ll.extend([w[:i] + '.' + w[i:] + '$' for i in range(len(w)+1)])
    # le "ou" de toutes ces conditions
    return '(' + '|'.join(ll) + ')'


def lookup(w):
    ll = open('liste.de.mots.francais.frgut.txt', encoding='latin1').readlines()
    if w:
        s=dist_pat(w); p=re.compile(s, re.U)
        return [w.rstrip() for w in ll if re.match(p,w)]
    else: return [x.rstrip() for x in ll if len(x.rstrip())==1]
In [22]:
print (lookup('ais'))
['agis', 'ai', 'aie', 'aies', 'ail', 'ails', 'air', 'airs', 'ais', 'aïs', 'aise', 'aisé', 'aisy', 'ait', 'amis', 'anis', 'ans', 'apis', 'ars', 'as', 'avis', 'axis', 'bais', 'bis', 'dais', 'dis', 'fais', 'fis', 'gais', 'gis', 'hais', 'jais', 'lais', 'lis', 'mais', 'mis', 'nais', 'ois', 'pais', 'pis', 'rais', 'ris', 'sais', 'sis', 'tais', 'vais', 'vis']
In [23]:
dist_pat('ais')
Out[23]:
'(.?is$|a.?s$|ai.?$|.ais$|a.is$|ai.s$|ais.$)'
In [ ]:
 
In [ ]: