Dateien zusammenfügen (nach Kennummer)

D

draobxinu

Jungspund
Hallo,

ich möchte Binärdateien mit einem Shellskript aus einem Verzeichnis zu einer neuen Datei zusammenfügen. Die Dateien sehen folgendermaßen aus:

datei_1_irgendwas
datei_10_irgendwas
datei_2_irgendwas

Folgender Auszug liefert mir die Dateien hintereinander weg.
#! /bin/bash
ls -al * | awk '{print $8}'

Wie kann ich ls dazu bewegen nach der Nummer zwischen den beiden Unterstrichen aufzulisten. Was muss ich machen um dann diese Dateien an cat zu übergeben um eine neue Datei zu erstellen? Ist die Sortierung überhaupt machbar oder sollte ich die fehlenden Zehner, Hunderter ... mit Nullen auffüllen?

Bin für jede Hilfe und Hinweise dankbar,
draobxinu
 
Wenn die Dateien lexikographisch richtig geordnet sind, z.B. aa.txt, ab.txt, ac.txt, ..., zz.txt, dann ist es ein leichtes diese mit cat wieder zu einer Datei zusammen zubauen.

cat *.txt > ganz.txt

In deinem Falle wirst du aber Probleme kriegen, da datei_10.txt vor datei_2.txt kommt. Also solltest du das mit Nullen auffüllen.


Das Gegenteil von cat ist in dem falle split. (Um aus einer großen Datei viele kleine zu machen)
 
Ich möchte das gerne in einem Shellskript automatisieren, da es sich um sehr viele Dateien handelt. Jeder Versuch die Ausgabe von
ls -al * | awk '{print $8}'
nach cat zu leiten schlugen fehl.
Kann man die Sortierung nicht durch ein ShellSkript lösen?
 
Zuletzt bearbeitet:
Würde es Dir helfen, wenn man die Dateien umbennt, also datei_1_irgendwas in datei_01_irgendwas? Oder kommt das nicht in Frage.

Gruss, Xanti

btw: nice nick ;)
 
Xanti schrieb:
Würde es Dir helfen, wenn man die Dateien umbennt, also datei_1_irgendwas in datei_01_irgendwas? Oder kommt das nicht in Frage.

Werde ich wohl so machen müssen :)
Dann reduziert sich das Problem auf den Vorschlag von hehejo. Könnte man die laufende Nummer nutzen um einen Dateibereich, wie datei_05_irgendwas bis datei_20_irgendwas zusammenzufügen?



Xanti schrieb:

Danke :)
 
Ungeprüft:

Code:
ls -1 * | perl -nl -e '$_=~/^(.*_)(\d+)(_.*)$/; $n=$1.sprintf("%02d", $2).$3; rename $_, $n'

Es nennt alle Files im Verzeichnis derart um: datei_1_irgendwas -> datei_01_irgendwas.

Gruss, Xanti
 
Zuletzt bearbeitet:
Danke für den String. Da muss ich mich heute Abend erstmal ein Weilchen hinsetzen um den zu verstehen :)
 
Hallo

Wenn schon mit perl, dann hab ich auch noch einen Vorschlag ohne Umbenennung.
Schnellschuss ungeprüft.
Code:
# wenn alles in einem Verzeichnis liegt:
cd /verzeichnis;
perl -e 'for (@ARGV) {(/datei_(\d+)_irgendwas/)?$h{sprintf "%02d",$1}=$_:1;}system "cat $h{$_}" for sort keys %h' * >/pfad/zum/resultat/ergebnis
:devil:
Wenn die nicht in einem Verzeichnis liegen, verfüttere einfach eine Ausgabe von ls oder find an diesen Einzeiler, statt den von mir verwendeten glob-Stern * zu benutzen ;)

Gruß Wolfgang
PS Hash ist doch was feines gelle.:D
 
@Wolfgang: Da hat er aber noch mehr dran zu kauen. ;)

p.s. Hash ist wirklich was feines. :)
 
Xanti schrieb:
@Wolfgang: Da hat er aber noch mehr dran zu kauen. ;)

Ja, nee is klar.
:D
Dafür erspart er sich das Umbenennen.
Ich hab ja schon map weggelasen, damit es einigermaßen verständlich lesbar bleibt.
Für Rückfragen steh ich gern zur Verfügung.

Gruß Wolfgang
 
Danke für Deinen String Wolfgang!

Irgendwie kann ich noch nicht richtig die Abarbeitungsreihenfolge erkennen. Der Stern am Ende steht wahrscheinlich für den Inhalt eines Verzeichnisses, unklar ist mir wie er das genau macht, da ein ls oder ähnliches fehlt. Wenn ich ein ls -all durch eine Pipe übergebe landet es wahrscheinlich im (@ARGV)?! wo jeder String durch den Reg.-ausdruck geprüft wird und die Hashtabelle $h aufgebaut wird. Ist hier das erste 'for' zu Ende? Wie passt das anschliessende cat da rein zumahl erst am Ende sortiert wird?! Fragen über Fragen :)

Eine Frage noch:
Wenn hinter dem datei_zahl_ etwas variables kommt, das nicht mit 'datei' übereinstimmt und am Ende eine einheitliche Endung aufweisst wie .ende (Bsp. datei_1_variablerTeil.ende, datei_10_variablerTeil.ende) muss dann der reguläre Ausdruck wie folgt lauten '(/datei_(\d+)_/)' oder auch '(/datei_(\d+)_*\.ende/)' ?

Bis dann,
draobxinu

P.S. Hab nicht gedacht das Perl so knackig ist :)
 
Da Wolfgang nicht da ist, versuch ich's mal zu erklären.

draobxinu schrieb:
Danke für Deinen String Wolfgang!

Irgendwie kann ich noch nicht richtig die Abarbeitungsreihenfolge erkennen. Der Stern am Ende steht wahrscheinlich für den Inhalt eines Verzeichnisses, unklar ist mir wie er das genau macht, da ein ls oder ähnliches fehlt.

* wird von der Shell interpretiert und der Inhalt des Verzeichnisses, so verhanden, wird substituiert. Gib einfach mal echo * ein, dann siehst Du, was * ist. Bei dieser Vorgehensweise wird vorausgesetzt, dass die Dateinamen keine Leerzeichen enthalten.

draobxinu schrieb:
Wenn ich ein ls -all durch eine Pipe übergebe landet es wahrscheinlich im (@ARGV)?! wo jeder String durch den Reg.-ausdruck geprüft wird und die Hashtabelle $h aufgebaut wird.

Richtig, @ARGV ist eine Liste, bestehend aus den Kommandozeilenargumenten, hier *. Und die Hashtabelle heisst %h. Eine Hashtabelle besteht in der Regel aus Schlüssel->Wert-Paaren. Wolfgang baut sich den Hash in der ersten for-Schleife derart auf: 01->datei_1_irgendwas, 12->datei_12_irgendwas...

draobxinu schrieb:
Ist hier das erste 'for' zu Ende? Wie passt das anschliessende cat da rein zumahl erst am Ende sortiert wird?! Fragen über Fragen :)

Nachdem er den Hash erstellt hat, führt er den Shellbefehl cat (durch system werden Shellbefehle abgesetzt) auf die Files (datei_1_irgendwas...) aus, die den sortierten Schlüsseln (01...) entsprechen.

draobxinu schrieb:
Eine Frage noch:
Wenn hinter dem datei_zahl_ etwas variables kommt, das nicht mit 'datei' übereinstimmt und am Ende eine einheitliche Endung aufweisst wie .ende (Bsp. datei_1_variablerTeil.ende, datei_10_variablerTeil.ende) muss dann der reguläre Ausdruck wie folgt lauten '(/datei_(\d+)_/)' oder auch '(/datei_(\d+)_*\.ende/)' ?

Code:
(/datei_(\d+)_.*\.ende/)

btw, ()?: ist ein if-then-else. Bei mehr Infos einfach perldoc in die Konsole eingeben.

draobxinu schrieb:
Bis dann,
draobxinu

P.S. Hab nicht gedacht das Perl so knackig ist :)

Perl ist noch viel knackiger ;)
 
Zuletzt bearbeitet:
Hallo
@Xanti schön erklärt. Danke dass du mir das Tippsen abgenommen hast.
8)
@draobxinu
Etwas möchte ich noch zu der Variante mit dem Dateinamen datei_NUM_Variable_ende und Verwendung meines Einzeilers anmerken.
Da es hier einen variablen Teil gibt, musst du selbst sicherstellen, dass die Ziffern eindeutig sind.
Wenn z.B. Namen wie datei_2_var1.ende und datei_2_var2.ende vorkommen, dann wird eine verschluckt werden. -> Genau die, die zuletzt an den Perlcode übergeben wird, wird berücksichtigt werden, weil der Hasheintrag 02 einfach überschrieben wird. Hashkeys sind immer eindeutig.
Auch darf es keine datei_01_ende und datei_1_ende nebeneinander geben.
Das ist ja auch für deinen Fall wichtig, da du ja Daten binär in der richtigen Reihenfolge verschmelzen willst.
Du musst also selbst genau wissen, welche Daten zusammengehören und einen eindeutigen numerischen Teil absichern.

Gruß Wolfgang
 
Zurück
Oben