Jak scalić wszystkie pliki (tekstowe) z katalogu w jeden?

89

Mam 14 plików, z których wszystkie są częścią jednego tekstu. Chciałbym połączyć je w jedno. Jak to zrobić?

Ivan
źródło

Odpowiedzi:

168

Jest to technicznie to, co catpowinien zrobić („konkatenate”), nawet jeśli większość ludzi używa go tylko do wysyłania plików na standardowe wyjście. Jeśli nadasz mu wiele nazw plików, wyprowadzi je wszystkie kolejno, a następnie możesz przekierować je do nowego pliku; w przypadku wszystkich plików po prostu użyj *(lub /path/to/directory/*jeśli nie jesteś jeszcze w katalogu), a twoja powłoka rozwinie go do wszystkich nazw plików

$ cat * > merged-file
Michał Mrożek
źródło
15
Uwaga: cytowane polecenie prawdopodobnie zrobi to, czego chce plakat, jeśli jest ponumerowane w taki sposób, że skorupa rozwija się *w „naturalnym” porządku. Jeśli masz „plik1.txt ... plik9.txt ... plik14.txt”, to nie zadziała, ponieważ plik1? .Txt będzie sortować między plikiem1.txt a plikiem2.txt. Musisz zmienić ich nazwę na „plik01.txt ... plik09.txt ... plik14.txt”. Powiedz, echo *jeśli nie jesteś pewien.
Warren Young,
2
@ Warren: dobra uwaga (lub możesz użyć zsh i ustawić jego numeric_glob_sortopcję).
Gilles
2
@ warren-young poprawny, użyteczny komentarz ostrzegawczy. Ale w moim przypadku kolejność nie ma znaczenia (ponieważ pliki zawierają proste instrukcje SQL wstawiające rekordy danych, które nie są zależne).
Ivan
2
Uwaga, jeśli liczba plików przekroczy określony limit, możesz uruchomić się z błędami, takimi jak - / bin / cat: lista argumentów jest za długa
Nupur
1
@ ARA1307 Tylko jeśli plik już istnieje; w przeciwnym razie glob zostanie rozwinięty, zanim powłoka otworzy plik do zapisu. Dobry punkt w tej sytuacji
Michael Mrozek
25

Jeśli twoje pliki nie znajdują się w tym samym katalogu, możesz użyć polecenia find przed konkatenacją:

find /path/to/directory/ -name *.csv -print0 | xargs -0 -I file cat file > merged.file

Bardzo przydatne, gdy pliki są już zamówione i chcesz je scalić w celu ich analizy.


Bardziej przenośny:

find /path/to/directory/ -name *.csv -exec cat {} + > merged.file

To może, ale nie musi, zachować porządek plików.

3nrique0
źródło
1
Jest to odpowiedni sposób, jeśli masz dużo plików. Unikasz błędu „zbyt długiej listy argumentów”.
Мати Тернер
2
Potrzebujesz -name „* .csv” zamiast -name * .csv - bez cudzysłowów nie powiedzie się.
Peteris,
Potrzeba cytowania zależy od wersji polecenia find, szczególnie w find i awk to problem, gdy jesteś na komputerze Mac, wersje obu programów są nieco stare. Jak dotąd na Ubuntu, Fedorze,
Debianie i CentOSie
Spodziewałbym się, że wersja bez cudzysłowu będzie działać, gdy w bieżącym katalogu nie będzie plików pasujących do wzorca "*.csv", ponieważ powłoka przekaże literał *do find.
RJHunter,
9

Komenda

$ cat * > merged-file

w rzeczywistości ma niepożądany efekt uboczny włączenia „scalonego pliku” do konkatenacji, tworząc plik ucieczki. Aby obejść ten problem, albo zapisz scalony plik w innym katalogu;

$ cat * > ../merged-file

lub użyj dopasowania wzorca, które zignoruje scalony plik;

$ cat *.txt > merged-file
Christopher Jones
źródło
14
cat * > merged-filedziała w porządku. Globs są przetwarzane przed utworzeniem pliku. Jeśli merged-filejuż istnieje, cat(przynajmniej mój) wykryje, że jest to plik wyjściowy i odmówi jego odczytania. JEŻELI plik już istnieje, a przekierowanie jest później w potoku, to oczywiście nie może tego zrobić, więc wtedy i tylko wtedy otrzymujesz plik niekontrolowany.
Kevin
catnie ma możliwości wykrycia, czy plik jest plikiem wyjściowym. Przekierowanie odbywa się w powłoce; catdrukuje tylko na standardowym wyjściu.
bfontaine,
8

Tak jak inni mówią tutaj ... Możesz użyć cat

Powiedzmy, że masz:

~/file01
~/file02
~/file03
~/file04
~/fileA
~/fileB
~/fileC
~/fileD

I chcesz tylko file01do file03i fileAdo fileC:

cat ~/file01 ~/file02 ~/file03 ~/fileA ~/fileB ~/fileC > merged-file

Lub używając rozszerzenia nawiasów klamrowych:

cat ~/file0{1..3} ~/file{A..C} > merged-file

Lub za pomocą bardziej rozbudowanego rozszerzenia nawiasów klamrowych:

cat ~/file{0{1..3},{A..C}} > merged-file

Lub możesz użyć forpętli:

for i in file0{1..3} file{A..C}; do cat ~/"$i"; done > merged-file
Florin Idita
źródło
1
Zauważ, że łańcuch [01-03]nie będzie działał jako wzór globowania.
Kusalananda
0

Możesz określić patternplik, a następnie scalić je wszystkie w następujący sposób:

cat *pattern* >> mergedfile
użytkownik182845
źródło
0

Inną opcją jest sed:

sed r 1.txt 2.txt 3.txt > merge.txt 

Lub...

sed h 1.txt 2.txt 3.txt > merge.txt 

Lub...

sed -n p 1.txt 2.txt 3.txt > merge.txt # -n is mandatory here

Lub bez przekierowania ...

 sed wmerge.txt 1.txt 2.txt 3.txt

Zauważ, że w ostatnim wierszu napisz również merge.txt (nie wmerge.txt!). Możesz użyć w "merge.txt", aby uniknąć pomyłek z nazwą pliku, i -n dla cichego wyjścia.

Oczywiście można także skrócić listę plików za pomocą symboli wieloznacznych. Na przykład w przypadku plików numerowanych, jak w powyższych przykładach, możesz określić zakres z nawiasami klamrowymi w następujący sposób:

sed -n w"merge.txt" {1..3}.txt
Harini
źródło