Verketten von Dateien und Einfügen einer neuen Zeile zwischen Dateien

127

Ich habe mehrere Dateien, mit denen ich mich befassen möchte cat. Sagen wir

File1.txt 
foo

File2.txt
bar

File3.txt
qux

Ich möchte mich darauf konzentrieren, dass die endgültige Datei wie folgt aussieht:

foo

bar

qux

Stattdessen mit üblich cat File*.txt > finalfile.txt

foo
bar 
qux

Was ist der richtige Weg, um es zu tun?

neversaint
quelle

Antworten:

120

Du kannst tun:

for f in *.txt; do (cat "${f}"; echo) >> finalfile.txt; done

Stellen Sie sicher, dass die Datei finalfile.txtnicht vorhanden ist, bevor Sie den obigen Befehl ausführen.

Wenn Sie verwenden dürfen, können awkSie Folgendes tun:

awk 'FNR==1{print ""}1' *.txt > finalfile.txt
Codaddict
quelle
10
AWK '{print $0}' *.txt
Timger
7
Dies hat den deutlichen Fehler, dass es entweder am Ende (von der ersten Alternative) oder am Anfang (von der zweiten Alternative) leere Zeilen geben wird. Sie können sich jedoch leicht dagegen schützen awk 'FNR==1 && NR > 1 ...'.
Tripleee
5
Wenn Sie >finalfile.txtnach dem setzen done, können Sie überschreiben anstatt anzuhängen, wodurch die Anforderung beseitigt wird, sicherzustellen, dass die Datei vor der Schleife fehlt oder leer ist.
Tripleee
53

Wenn Sie nur wenige Dateien haben, die Sie auflisten können, können Sie die Prozessersetzung in Bash verwenden und zwischen jedem Dateipaar eine neue Zeile einfügen:

cat File1.txt <(echo) File2.txt <(echo) File3.txt > finalfile.txt
Robert Tupelo-Schneck
quelle
1
Wunderschönen! Vielen Dank.
Bob Kocisko
Dies funktionierte gut für mich, damit meine Letsencrypt-Zertifikate PEM-Dateien erstellen konnten.
Leeman24
35

Wenn ich es tun würde, würde ich sed verwenden:

sed -e '$s/$/\n/' -s *.txt > finalfile.txt

In diesem sed-Muster hat $ zwei Bedeutungen: Erstens entspricht es nur der letzten Zeilennummer (als Bereich von Zeilen, auf die ein Muster angewendet werden soll) und zweitens dem Zeilenende im Substitutionsmuster.

Wenn Ihre Version von sed keine hat -s(Eingabedateien separat verarbeiten), können Sie dies alles als Schleife ausführen:

for f in *.txt ; do sed -e '$s/$/\n/' $f ; done > finalfile.txt
Flexo
quelle
3
Oder in GNU sed:sed -s '$G' *.txt > finalfile.txt
Ruud Helderman
Nur ein Stream! Dies sollte die akzeptierte Antwort sein!
Yassine ElBadaoui
Seid vorsichtig, ich habe gerade meinen PC abgestürzt, weil ich findanstelle von verwendet habe *.txt, was bedeutete, dass die Datei an sich selbst angehängt wurde!
Xerus
11

Sie können es verwenden, xargswenn Sie möchten, aber die Hauptidee ist immer noch dieselbe:

find *.txt | xargs -I{} sh -c "cat {}; echo ''" > finalfile.txt
Nick Roz
quelle
1
Vielen Dank. Ich finde es xargsviel einfacher zu benutzen als Loops in Bash.
RawwrBag
9

Dies funktioniert in Bash:

for f in *.txt; do cat $f; echo; done

Im Gegensatz zu Antworten mit >>(Anhängen) kann die Ausgabe dieses Befehls in andere Programme geleitet werden.

Beispiele:

  • for f in File*.txt; do cat $f; echo; done > finalfile.txt
  • (for ... done) > finalfile.txt (Parens sind optional)
  • for ... done | less (Rohrleitungen in weniger)
  • for ... done | head -n -1 (Dadurch wird die nachfolgende Leerzeile entfernt.)
user3780389
quelle
7

So habe ich es gerade unter OsX 10.10.3 gemacht

for f in *.txt; do (cat $f; echo '') >> fullData.txt; done

da der einfache 'echo'-Befehl ohne Parameter in keinen neuen Zeilen eingefügt wurde.

lbrutti
quelle
Dadurch wird die Zeichenfolge am Ende der Datei platziert. Wie kann ich es zwischen die einzelnen Dateien einfügen ?
Onassar
3

In Python verkettet sich dies mit Leerzeilen zwischen Dateien (dies ,unterdrückt das Hinzufügen einer zusätzlichen nachgestellten Leerzeile):

print '\n'.join(open(f).read() for f in filenames),

Hier ist der hässliche Python-Einzeiler, der von der Shell aufgerufen werden kann und die Ausgabe in eine Datei druckt:

python -c "from sys import argv; print '\n'.join(open(f).read() for f in argv[1:])," File*.txt > finalfile.txt
user3780389
quelle