Verketten mehrerer Textdateien zu einer einzigen Datei in Bash

305

Was ist der schnellste und pragmatischste Weg, um alle * .txt-Dateien in einem Verzeichnis in einer großen Textdatei zu kombinieren?

Derzeit verwende ich Windows mit Cygwin, damit ich Zugriff auf BASH habe.

Windows-Shell-Befehl wäre auch schön, aber ich bezweifle, dass es einen gibt.

Yada
quelle

Antworten:

537

Dadurch wird die Ausgabe an all.txt angehängt

cat *.txt >> all.txt

Dies überschreibt all.txt

cat *.txt > all.txt
Robert Greiner
quelle
30
Sie können auf ein Problem stoßen, bei dem es all.txt in all.txt katzt ... Ich habe dieses Problem manchmal mit grep, nicht sicher, ob Katze das gleiche Verhalten hat.
Rmeador
8
@rmeador ja, das stimmt, wenn all.txt bereits existiert, tritt dieses Problem auf. Dieses Problem wird gelöst, indem die Ausgabedatei mit einer anderen Erweiterung versehen oder all.txt in einen anderen Ordner verschoben wird.
Robert Greiner
2
cat * .txt >> tmp; mv tmp all.txt (und stellen Sie sicher, dass all.txt vorher nicht existiert)
Renaud
16
Ich bekomme "Argumentliste zu lang" - ich denke, es kann nicht mehr als 40.000 Dateien verarbeiten.
Matt
32
Vermeiden Sie zu lange Argumente mit:echo *.txt | xargs cat > all.txt
5heikki
145

Denken Sie daran, dass die Shell bei allen bisher angegebenen Lösungen die Reihenfolge festlegt, in der die Dateien verkettet werden. Für Bash, IIRC, ist das eine alphabetische Reihenfolge. Wenn die Reihenfolge wichtig ist, sollten Sie die Dateien entweder entsprechend benennen (01file.txt, 02file.txt usw.) oder jede Datei in der Reihenfolge angeben, in der sie verkettet werden soll.

$ cat file1 file2 file3 file4 file5 file6 > out.txt
Chinmay Kanchi
quelle
33

Der Windows-Shell-Befehl typekann dies tun:

type *.txt >outputfile

Der typeBefehl type schreibt auch Dateinamen in stderr, die nicht vom >Umleitungsoperator erfasst werden (sondern auf der Konsole angezeigt werden).

Greg Hewgill
quelle
2
Beachten Sie jedoch, dass wenn Sie die Ausgabedatei im selben Verzeichnis wie die Originaldatei ablegen, dies zu einer Duplizierung führt, da die neue Ausgabedatei auch zweimal kombiniert wird.
CathalMF
26

Sie können die Windows-Shell verwenden, copyum Dateien zu verketten.

C:\> copy *.txt outputfile

Aus der Hilfe:

Geben Sie zum Anhängen von Dateien eine einzelne Datei als Ziel an, jedoch mehrere Dateien als Quelle (mit Platzhaltern oder im Format Datei1 + Datei2 + Datei3).

Carl Norum
quelle
Dies als die IMHO sauberste Lösung ohne Nebenwirkungen, über die Anfänger stolpern könnten, wird leider nicht genug gewürdigt :-(
Grmpfhmbl
OP fragte nach Bash.
Big Rich
2
Hast du die Frage gelesen? "Windows Shell-Befehl wäre auch schön ..."
Carl Norum
8

Seien Sie vorsichtig, da keine dieser Methoden mit einer großen Anzahl von Dateien funktioniert. Persönlich habe ich diese Zeile verwendet:

for i in $(ls | grep ".txt");do cat $i >> output.txt;done

EDIT: Als jemand in den Kommentaren gesagt, können Sie ersetzen $(ls | grep ".txt")mit$(ls *.txt)

BEARBEITEN: Dank der Erfahrung von @gnourf_gnourf ist die Verwendung von glob die richtige Methode, um Dateien in einem Verzeichnis zu durchlaufen . Folglich müssen blasphemische Ausdrücke wie $(ls | grep ".txt")durch ersetzt werden *.txt(siehe Artikel hier ).

Gute Lösung

for i in *.txt;do cat $i >> output.txt;done
Jacobe2169
quelle
1
Warum nicht for i in $(ls *.txt);do cat $i >> output.txt;done?
Streamofstars
2
Obligatorischer ParsingLs- Link zusammen mit einer Abwertung (und Sie verdienen mehr als eine Abwertung, da ls | grepes sich um ein ernsthaft schlechtes Antimuster handelt).
gniourf_gniourf
Ich habe eine Gegenstimme von mir erhalten, weil es willkürliche Tests / Operationen nach Dateinamen vor der Ausgabe ermöglicht und es schnell und einfach und gut zum Üben ist. (In meinem Fall wollte ich: für i in *; Echo -e "\ n $ i: \ n"; Katze $ 1; fertig)
Nathan Chappell
Würde das nicht ls *.txtscheitern, wenn zu viele Dateien vorhanden sind (Argumentliste zu langer Fehler)?
Rafael Almeida
6

Der pragmatischste Weg mit der Shell ist der Befehl cat. andere Möglichkeiten umfassen,

awk '1' *.txt > all.txt
perl -ne 'print;' *.txt > all.txt
Ghostdog74
quelle
1
Dies sollte für die meisten Umstände die richtige Antwort sein. Wenn eine Textdatei keine leere neue Zeile enthält, werden mit der oben beschriebenen catMethode die letzte und die erste Zeile benachbarter Dateien verkettet.
Mootmoot
6

Wie wäre es mit diesem Ansatz?

find . -type f -name '*.txt' -exec cat {} + >> output.txt
GPrathap
quelle
Da OP angibt, dass sich die Dateien im selben Verzeichnis befinden, müssen Sie sie möglicherweise -maxdepth 1dem findBefehl hinzufügen .
Codeforester
1
Funktioniert hervorragend mit einer großen Anzahl von Dateien, bei denen der Ansatz der akzeptierten Antwort fehlschlägt
amine
Ah, ich wünschte ich wüsste was dieses Plus und die doppelte Weiterleitung bedeuten ...
hallo_earth
Dies sollte die richtige Antwort sein. In einem Shell-Skript funktioniert es ordnungsgemäß. Hier ist eine ähnliche Methode, wenn Sie die Ausgabe sortieren möchten:sort -u --output="$OUTPUT_FILE" --files0-from=- < <(find "$DIRECTORY_NAME" -maxdepth 1 -type f -name '*.txt' -print0)
steveH
3
type [source folder]\*.[File extension] > [destination folder]\[file name].[File extension]

Beispielsweise:

type C:\*.txt > C:\1\all.txt

Das nimmt alle txt-Dateien im Ordner C: \ und speichert sie im Ordner C: \ 1 unter dem Namen all.txt

Oder

type [source folder]\* > [destination folder]\[file name].[File extension]

Beispielsweise:

type C:\* > C:\1\all.txt

Dadurch werden alle im Ordner vorhandenen Dateien übernommen und der Inhalt in C: \ 1 \ all.txt abgelegt

Ori
quelle
0

Sie können dies tun: cat [directory_path]/**/*.[h,m] > test.txt

Wenn Sie {}die Erweiterung der Dateien verwenden, die Sie suchen möchten, liegt ein Sequenzierungsproblem vor.

Michael-Zhang
quelle
0

Wenn Sie auf ein Problem stoßen, bei dem all.txt in all.txt umgewandelt wird, können Sie versuchen, zu überprüfen, ob all.txt vorhanden ist oder nicht, falls vorhanden, entfernen Sie es

So was:

[ -e $"all.txt" ] && rm $"all.txt"

Löwe
quelle
cat *.txt > all.txt >Befehl überschreibt all.txt, falls vorhanden, >>fügt Daten zu vorhandener Datei hinzu
Oleg Bondarenko
-4

das alles ist böse ....

ls | grep *.txt | while read file; do cat $file >> ./output.txt; done;

einfaches Zeug.

kSiR
quelle
6
Eeek! Tu das nicht. Dofind . -iname "*.txt" -maxdepth 1 -exec cat {} >> out.txt \;
Chinmay Kanchi