2016-03-24 2 views
1

Ich habe ein Python-Skript (nennen wir es myscript.py) Ich möchte für eine Reihe von Dateien, die in einer verschachtelten Verzeichnisstruktur gelten. Ich werde die Aufrufe dieses Skripts parallel auf einer Cluster-Umgebung ausführen, daher möchte ich zu diesem Zweck ein kurzes Bash-Skript schreiben.rekursiv navigieren das Dateisystem, um Dateien in Paaren zu analysieren

So Paare von Dateien wie xyz_1.gz und xyz_2.gz gegeben, die in Ordnern wie verschachtelt sind:

A > ... > C1 > xyz_1.gz 
A > ... > C1 > xyz_2.gz 
A > ... > C1 > bunch of other files 
A > ... > C2 > xyy_1.gz 
A > ... > C2 > xyy_2.gz 
A > ... > C2 > bunch of other files 
A > ... > C3 > zzz_1.gz 
A > ... > C3 > zzz_2.gz 
A > ... > C3 > bunch of other files 
A > B > some other things 

oben Es ist ein dummes Beispiel, aber ich hoffe, dass es die Struktur zumindest vermittelt.

Ich möchte in der Lage sein, über die Verzeichnisstruktur zu durchlaufen und mein Skript aufrufen:

myscript.py xyz_1.gz xyz_2.gz outputfile 

Derart, dass die Ausgabedateien in den entsprechenden Ordner landen.

meisten rekursiven Lösungen, die ich gesehen habe bisher entweder find oder grep für jede einzelne Datei verwenden, jedoch muss ich die Lage als gut, sie paarweise zu erhalten und auf die Festplatte an der entsprechenden Stelle zu schreiben.

Irgendwelche Vorschläge?

EDIT: Nach den Antworten, die ich bisher habe, wollte ich, dass die folgenden drei Parameter klären, werden nicht im Voraus mir bekannt:

  1. Tiefe Unterverzeichnisse die GZ-Dateien zu halten, dh ich weiß nicht, wie viele Zwischenverzeichnisse existieren zwischen
  2. Namen der Unterverzeichnisse
  3. Namen der Dateien, mit der Ausnahme, dass sie neben dem _1/_2 Suffix identisch sind

Antwort

1

(. Antwort auf die bearbeitete Frage)

Es ist etwas schwieriger (weniger lesbar) in der Schale zu erreichen, so habe ich auf den Python zurückgegriffen:

#!/usr/bin/env python3 
import os 
import re 
import pprint 
from sets import Set 
from subprocess import call 

group1 = {} # collect here the filenames for _1 
group2 = {} # collect here the filenames for _2 

for root, directories, filenames in os.walk('.'): 
     for filename in filenames: 
       ff = os.path.join(root,filename) 
       if filename.endswith("_1.txt"): 
         base = re.sub('_1\.txt$','', ff) 
         group1[base] = ff 
       if filename.endswith("_2.txt"): 
         base = re.sub('_2\.txt$','', ff) 
         group2[base] = ff 

#pprint.pprint(group1) 
#pprint.pprint(group2) 

# find common ones: the dirs which contain the files with the common prefix: 
list1 = Set(group1.keys()).intersection(Set(group2.keys())) 

#pprint.pprint(list1) 

# call the myscript.py 
cwd = os.getcwd() 
for base in list1: 
     path, filename = os.path.split(base) 
     #print path," ",filename 
     try: 
       os.chdir(path) 
       call(['echo', 'myscript.py', filename+"_1.txt", filename+"_2.txt", "outputfile"]) 
     finally: 
       os.chdir(cwd) 

(Sorry für den miesen Python-Stil : ich bin ein Programmierer Perl tatsächlich)


meisten rekursiven Lösungen, die ich bisher für jede einzelne Datei verwenden gesehen haben entweder finden oder grep aber ich brauche auch die Lage, t zu erhalten. Saum paarweise und schreibe auf die entsprechende Stelle.

Nicht iterieren über Dateien - iterieren über Verzeichnisse. Beispiel in der Schale:

find -type d -print | 
while read DIR; do 
    test -r $DIR/xyz_1.gz -a -r $DIR/xyz_2.gz -a -r $DIR/some_other_file || continue 
    (cd $DIR; myscript.py xyz_1.gz xyz_2.gz outputfile) 
done 

Oder alternativ können Sie noch Dateien iterieren, find Prüfung für eine der Dateien für uns zu lassen.Dann extrahiert Verzeichnis aus dem gefundenen Dateinamen:

find -type f -name xyz_1.gz -print | 
while read FN; do 
    DIR=`dirname $FN` 
    test -r $DIR/xyz_2.gz -a -r $DIR/some_other_file || continue 
    (cd $DIR; myscript.py xyz_1.gz xyz_2.gz outputfile) 
done 

Auch können Sie die cd $DIR bewegen (os.chdir() am Anfang; Verzeichnis passiert entweder als Argument oder als env var) in den Python-Skript selbst, sowie die Suchen Sie nach den Eingabedateien (beenden Sie still, wenn die Dateien nicht vorhanden sind).

+0

Ich mag die Idee, die Ordner von 'finden' und Iterieren über sie zu bekommen, um zu sehen, ob die Dateien existieren. Wie ich jedoch in meinem Beitrag zu der Frage erwähnt habe, weiß ich nicht, wie die Dateien heißen, außer sie haben das Format xxx_ [1/2] .gz – posdef

+0

@posdef, ich bin krank zuhause, also mein Script-Fu ist im Moment etwas außer Form. Ich werde versuchen, die Antwort einige Tage später zu aktualisieren. Grobe Umrisse: finde alle '_1.gz' Dateien und setze jedem Zeilennamen den Namen + Stiel des Dateinamens voran (Stem == alles außer' _1.gz'); Mach das gleiche mit '_2.gz' Dateien; Führen Sie die Listen über den Befehl 'join' aus. (Sie können das gleiche in der Python mit Wörterbüchern tun: Schlüssel ist der Name + Stamm des Dateinamens, Wert ist der Dateiname; finden Sie gemeinsame Schlüssel in den beiden Dicts) – Dummy00001

+0

Kein Problem, Kumpel, ich werde es herausfinden :) – posdef

0

Hier ist die Bash-Skript, das folgende Material ausführen:

for i in */*/*.gz 
do 
    echo "$i" 
done | sort | while read -r line || [[ -n "$line" ]] 
do 
    read -r nextline 
    $(cd $(dirname "$line") && python3 ~/A/myscript.py "$line" "$nextline" ./outputfile) && echo "Success" 
done 

Script in Bezug auf die Rekursivität ziemlich starr ist, aber ich habe es angewendet entsprechend Ihrer Verzeichnisstruktur

nicht genau wissen, wie viel Dateien gibt es aber so etwas wie für Sie arbeiten:

[email protected] ~/A$ ls -R 
.: 
B/ B1/ B2/ myscript.py script.bash 

./B: 
C1/ 

./B/C1: 
some_other_file xyz_1.gz xyz_2.gz 

./B1: 
C2/ 

./B1/C2: 
some_other_file xyy_1.gz xyy_2.gz 

./B2: 
C3/ 

./B2/C3: 
some_other_file zzz_1.gz zzz_2. 
[email protected] ~/A$ ./script.bash 
Success 
Success 
Success 
[email protected] ~/A$ cat B/C1/outputfile 
B/C1/xyz_1.gz 
B/C1/xyz_2.gz 
[email protected] ~/A$ cat B1/C2/outputfile 
B1/C2/xyy_1.gz 
B1/C2/xyy_2.gz 
[email protected] ~/A$ cat B2/C3/outputfile 
B2/C3/zzz_1.gz 
B2/C3/zzz_2.gz 
[email protected] ~/A$ 
$ 

ich Dummy python-Skript erstellt haben, die aus den Dateinamen schreibt, die gegeben sind es als Argumente. Das ist das Python-Skript:

+0

Danke für die Antwort, aber da ich die genaue Tiefe der Hierarchie im Voraus nicht kenne, kann ich mich nicht auf zwei Schritte der Rekursion verlassen. Ich habe die Frage zur Klärung aktualisiert – posdef