
Ich habe viele Ordner und Dateien, das ist die Struktur, die ich habe
26-09-2016/CHANGELOG_20160926.TXT
26-09-2016/FILE_CHANGELOG_20160926.TXT
27-09-2016/CHANGELOG_20160927.TXT
27-09-2016/FILE_CHANGELOG_20160927.TXT
Ich brauche die folgende Ausgabe. Alle Dateien mit Namen wie CHANGELOG_*.TXT
sollen zusammengeführt und mit einer separaten neuen Zeile in eine Datei wie eingefügt werden CHANGELOG_20160926-20160930.TXT
, und alle Dateien mit Namen FILE_CHANGELOG_*.TXT
sollen zusammengeführt und mit einer separaten neuen Zeile in eine Datei wie eingefügt werden FILE_CHANGELOG_20160926-20160930.TXT
.
Wie kann ich das machen?
Antwort1
Da Sie keine Sprachanforderungen angegeben haben, hier eine Möglichkeit mit Python 3.
#/usr/bin/env python3
from glob import glob
from os.path import basename
import re
for prefix in ('CHANGELOG', 'FILE_CHANGELOG'):
files = dict((int(re.split('[_.]', basename(f))[-2]), f)
for f in glob('*-*-*/%s_*.TXT' % prefix))
out_file = '%s_%d-%d.TXT' % (prefix, min(files.keys()), max(files.keys()))
with open(out_file, 'w') as f_out:
for date in sorted(files.keys()):
with open(files[date]) as f_in:
for line in f_in:
f_out.write(line)
f_out.write("\n")
Es verwendet im Wesentlichen glob
und basename
zum Auflisten und Parsen von Dateinamen und sortiert sie nach Datum. Die Min-/Max-Werte werden zum Erstellen des Ausgabedateinamens verwendet und alle Dateien werden der Reihe nach dort geschrieben. Vergessen Sie nicht, die Muster an Ihre tatsächliche Verzeichnisstruktur anzupassen, falls dies erforderlich ist. Führen Sie dann einfach chmod
und aus:
$ chmod +x script.py
$ ./script.py
Antwort2
Lösung inTXR:
Behandeln wir dies zunächst als Textverarbeitungsaufgabe und gehen davon aus, dass wir eine Beispielliste mit Pfadnamen für eine Eingabedatei namens haben paths
. Wir wandeln diese Dateigruppen paths
in Shell-Befehle um und erzeugen die erforderlichen Ausgabedateien:cat
@(do
(defstruct file-info nil
full-name
root-name
date-key
(:method equal (self) self.date-key)))
@(collect :vars (files))
@ (all)
@dd-@mm-@yyyy/@*{name}_@yyyy@[email protected]
@ (and)
@path
@ (end)
@ (bind files @(new file-info full-name path root-name name
date-key ^(,yyyy ,mm ,dd)))
@(end)
@(do
(let ((h (group-by (usl root-name) files :equal-based)))
[hash-update h sort]
(dohash (name flist h)
(let ((start (find-min flist))
(end (find-max flist))
(paths (mapcar (usl full-name) flist)))
(put-line `cat @{paths " "} >\ \
@{start.root-name}_@{start.date-key ""}- \
@{end.date-key ""}.TXT`)))))
Laufen:
$ txr catfiles.txr paths
cat 26-09-2016/CHANGELOG_20160926.TXT 27-09-2016/CHANGELOG_20160927.TXT > CHANGELOG_20160926-20160927.TXT
cat 26-09-2016/FILE_CHANGELOG_20160926.TXT 27-09-2016/FILE_CHANGELOG_20160927.TXT > FILE_CHANGELOG_20160926-20160927.TXT
Um auf realen Pfaden zu arbeiten und die cat
Befehle auszuführen, sind einfache Änderungen erforderlich:
@(do
(defstruct file-info nil
full-name
root-name
date-key
(:method equal (self) self.date-key)))
@(next :list (glob "*/*.TXT"))
@(collect :vars (files))
@ (all)
@dd-@mm-@yyyy/@*{name}_@yyyy@[email protected]
@ (and)
@path
@ (end)
@ (bind files @(new file-info full-name path root-name name
date-key ^(,yyyy ,mm ,dd)))
@(end)
@(do
(let ((h (group-by (usl root-name) files :equal-based)))
[hash-update h sort]
(dohash (name flist h)
(let ((start (find-min flist))
(end (find-max flist))
(paths (mapcar (usl full-name) flist)))
(sh `cat @{paths " "} >\ \
@{start.root-name}_@{start.date-key ""}- \
@{end.date-key ""}.TXT`)))))
Die einzigen Änderungen sind die Hinzufügung von , @(next :list (glob "*/*.TXT"))
um den Eingabescan über eine Liste von Pfaden umzuleiten, die aus dem Dateisystem globuliert wurden, und ein Wechsel von put-string
zu sh
, um die cat
Befehle ausführen zu lassen.
Wenn die Dateilisten sehr groß sein können, stoßen wir auf die Übergabegrenzen von OS-Befehlen/Argvs: Wir können sie nicht in einem einzigen Befehl caten.
Eine mögliche Lösung hierfür besteht darin, den letzten Teil des Codes wie folgt zu ändern:
@(do
(let ((h (group-by (usl root-name) files :equal-based)))
(hash-update h (op sort))
(dohash (name flist h)
(let* ((start (find-min flist))
(end (find-max flist))
(paths (mapcar (usl full-name) flist))
(target `@{start.root-name}_@{start.date-key ""}- \
@{end.date-key ""}.TXT`))
(sh `> @target`)
(each ((group-of-ten (tuples 10 paths)))
(sh `cat @{group-of-ten " "} >> @target`))))))
Stellen Sie also für jede Datei > file
sicher, dass sie existiert und auf Null gekürzt wird. Fügen Sie dann cat ... >> file
die Protokolle in Zehnergruppen daran an.