2011-09-24 20 views
14

Perl ha una piccola utility chiamata find2perl che tradurrà (abbastanza fedelmente) una riga di comando per l'utilità Unix find in uno script Perl per fare lo stesso.Equivalente Python di find2perl

Se si dispone di un comando find come questo:

find /usr -xdev -type d -name '*share' 

         ^^^^^^^^^^^^ => name with shell expansion of '*share' 
       ^^^^ => Directory (not a file) 
      ^^^ => Do not go to external file systems 
    ^^^ => the /usr directory (could be multiple directories 

Essa trova tutte le directory che terminano in share sotto /usr

Ora lanciate find2perl /usr -xdev -type d -name '*share' ed emetterà uno script Perl a fare lo stesso. È quindi possibile modificare lo script per l'uso.

Python ha os.walk() che ha certamente la funzionalità necessaria, ricorsivo elenco di directory, ma ci sono grandi differenze.

Prendere il caso semplice di find . -type f -print per trovare e stampare tutti i file nella directory corrente. Un'implementazione naive usando os.walk() sarebbe:

for path, dirs, files in os.walk(root): 
    if files: 
     for file in files: 
      print os.path.join(path,file) 

Tuttavia, questo produrrà risultati diversi che digitare find . -type f -print nel guscio.

Sono stato anche testato vari os.walk() loop contro:

# create pipe to 'find' with the commands with arg of 'root' 
find_cmd='find %s -type f' % root 
args=shlex.split(find_cmd) 
p=subprocess.Popen(args,stdout=subprocess.PIPE) 
out,err=p.communicate()  
out=out.rstrip()   # remove terminating \n 
for line in out.splitlines() 
    print line 

La differenza è che os.walk() conta link come file; trovare li salta.

Quindi una corretta applicazione che è lo stesso di file . -type f -print diventa:

for path, dirs, files in os.walk(root): 
    if files: 
     for file in files: 
      p=os.path.join(path,file) 
      if os.path.isfile(p) and not os.path.islink(p): 
       print(p) 

Dal momento che ci sono centinaia di permutazioni di trovare primarie e diversi effetti collaterali, questo diventa molto tempo per provare tutte le varianti. Dal find è il gold standard nel mondo POSIX su come contare i file in un albero, farlo nello stesso modo in Python è importante per me.

Quindi esiste un equivalente di find2perl che può essere utilizzato per Python? Finora ho appena usato find2perl e poi manualmente la traduzione del codice Perl. Questo è difficile perché gli operatori di test del file Perl sono different rispetto ai test dei file Python in os.path a volte.

+0

Io suggerirei parte della risposta potrebbe essere trovato qui: http://stackoverflow.com/questions/4639506/os- walk-with-regex Spiacente, non so find/find2perl abbastanza per aiutare di più. * (forse anche http://stackoverflow.com/questions/5141437/filtering-os-walk-dirs-and-files)* –

risposta

2

Ci sono un paio di osservazioni e diversi pezzi di codice per aiutarti lungo la strada.

In primo luogo, Python può eseguire codice in questa forma, proprio come il Perl:

cat code.py | python | the rest of the pipe story... 

find2perl è un modello di codice intelligente che emette una funzione Perl basato su un modello di ritrovamento. Quindi, replica questo modello e non avrai le "centinaia di permutazioni" che stai percependo.

In secondo luogo, i risultati da find2perl non sono perfetti proprio come ci sono potenzialmente differenze tra le versioni di find, come GNU o BSD.

In terzo luogo, per impostazione predefinita, os.walk è in basso; find è in alto. Ciò rende diversi risultati se l'albero della directory sottostante sta cambiando mentre lo si ricorre.

Ci sono due progetti in Python che possono essere d'aiuto: twander e dupfinder. Ognuno si sforza di essere os indipendente e ognuno ricorre al file system come find.

Se modello di un generale find come la funzione in Python, impostare os.walk la ricorsione dall'alto verso il basso, l'uso glob di replicare l'espansione della shell, e utilizzare parte del codice che trovate in questi due progetti, è possibile replicare find2perl senza troppo difficoltà.

Spiacente non ho potuto puntare a qualcosa di pronto a partire per le vostre esigenze ...

4

Se stai cercando di reimplementare tutti find, allora sì, il codice sta per arrivare peloso. find è piuttosto peloso tutto da solo.

Nella maggior parte dei casi, tuttavia, non si sta tentando di replicare il comportamento completo di find; stai eseguendo un compito molto più semplice (ad es. "trova tutti i file che terminano con .txt"). Se hai veramente bisogno di tutto il find, esegui semplicemente find e leggi l'output. Come dici tu, è il gold standard; potresti anche solo usarlo.

spesso mi scrivono codice che legge i percorsi su stdin solo così posso fare questo:

find ...a bunch of filters... | my_python_code.py 
+1

Questo funziona solo supponendo che il tuo ambiente di programma di destinazione sia su Unix tho. La bellezza di 'find2perl' è che puoi scrivere qualcosa su Unix ed eseguirlo ovunque che Perl funzioni - su Windows per esempio. –

1

Penso glob potrebbe aiutare nell'implementazione di questo.

1

Ho scritto uno script Python per utilizzare os.walk() per cercare e sostituire; potrebbe essere una cosa utile da guardare prima di scrivere qualcosa di simile.

Replace strings in files by Python

e l'eventuale sostituzione di Python per find (1) sta per affidarsi pesantemente al os.stat() per controllare varie proprietà del file. Ad esempio, ci sono flag per trovare (1) che controllano la dimensione del file o l'ultima data/ora modificata.