2. december

Find dine filer

Dagens program er et af de mere avancerede man finder på et almindeilgt UNIX/Linux-system, men heldigvis er det søndag, så der er god tid til at fordøje stoffet.

2. december - find

Når man skal finde filer på et UNIX/Linux-system, er det et absolut must at kende til 'find'. Nærmest lige meget hvilket kriterium du ønsker at lægge til grund for din søgning så kan 'find' klare det.

Lad os starte med at søge efter JPEG-billeder af Tux:

find . -name "Tux*.jpg"
Det kræver nok lidt forklaring.

Det første argument (punktummet) fortæller find hvor den skal starte sin søgning, et punktum betegner det katalog man står i, andre muligheder er "/" der ville få find til at gennemsøge hele filsystemet (men naturligvis kun de kataloger man har læserettigheder til) eller "~" der ville få find til at gennemsøge ens hjemmekatalog. De to sidste argumenter udgør et kriterium, det andet argument (-name) fortæller at søgekriteriet vedrører filnavnet, og det sidste argument er det mønster filnavnet skal matche.

Hvis du ønsker både at finde filen "Tux-1.jpg" og "tux-2.JPG" kan du bede 'find' om ikke at skelne mellem små og store bogstaver ved at bruge 'iname' i stedet for 'name'.

Nogle gange vil man gerne søge udfra flere kriterier på en gang, det kan 'find' også klare. Hvis man f.eks. vil finde alle de HTML-filer man ikke har rettet i inden for den seneste uge, kan man gøre sådan her:

find . -name "*.html" -mtime +7

Starten ligner det foregående eksempel, men det sidste kriterium er nyt. Det siger at den seneste ændring skal være foretaget for mere end 7 (+7) dage siden.

Hvis vi i stedet vil have de filer man har rettet i inden for den seneste uge, er der to muligheder. Man kan ændre '+7' til '-7', eller man kan negere kriteriet ved at sætte '-not' ind foran.

Nu er det sjældent man vil vide hvilke filer man har liggende bare for at vide det, som oftest vil man gerne gøre noget ved filerne. Heldigvis har 'find' også en indbygget mulighed for dette. Hvis man nu gerne vil vide hvor mange linier der er i alle ens HTML-filer kan man gøre følgende:

find . -name "*.html" -exec wc -l "{}" \;

Det ser besværligt ud, men det er ikke så slemt. Først siger vi til 'find' at den ikke bare skal skrive de filnavne den finder ud men i stedet udføre en kommando på dem. Derefter angiver vi kommandoen 'wc -l' og med "{}" fortæller vi 'find' hvor den skal placere filnavnene. Det afsluttende '\;' fortæller find at her slutter den kommando den skal udføre på de fundne filer.

Den netop beskrevne metode er desværre temmelig langsom, den starter nemlig en ny 'wc'-proces op for hver eneste fil. Heldigvis findes der et smart lille program der kan få det til at gå langt hurtigere, løsningen er:

find . -name "*.html" | xargs wc -l

Først har vi en velkendt 'find'-kommando, så beder vi med '|' kommandofortolkeren om at sende uddata videre til det program der står bagefter. Programmet 'xargs' tager sit inddata (som var alle filnavnene fra 'find') og deler det op i grupper og kalder så den efterfølgende kommando en gang per gruppe. Grupperne bliver som standard lavet så store som muligt (der er en grænse for hvor lange kommandolinier kan være), og der bliver derfor startet så få 'wc'-processer som muligt.

Desværre virker den netop beskrevne kommando ikke hvis nogle af filnavnene indeholder mellemrum (eller andre specielle tegn), men det kan heldigvis klares med en lille ændring:

find . -name "*.html" -print0 | xargs -0 wc -l

Her instruerer vi først med '-print0' 'find' om at udskrive filnavnene på et speciel måde, og derefter med '-0' 'xargs' om at forstå dem på denne måde.

Dette er kun en meget kort introduktion til 'find' som man kunne skrive utroligt meget om. Slutteligt vil jeg lige nævne at blandt de ting man kan få find til at søge på er, ejerskab, rettigheder og type (om det er en almindelig fil, et katalog, en symbolsk henvisning, ...).