Łączenie plików i wstawianie nowego wiersza między plikami


127

Mam wiele plików, z którymi chcę się połączyć cat. Powiedzmy

File1.txt 
foo

File2.txt
bar

File3.txt
qux

Chcę konkatować, aby ostateczny plik wyglądał następująco:

foo

bar

qux

Zamiast tego ze zwykłym cat File*.txt > finalfile.txt

foo
bar 
qux

Jak to zrobić we właściwy sposób?


Odpowiedzi:


121

Możesz to zrobić:

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

Upewnij się, że plik finalfile.txtnie istnieje, zanim uruchomisz powyższe polecenie.

Jeśli masz prawo do korzystania awk, możesz:

awk 'FNR==1{print ""}1' *.txt > finalfile.txt

10
AWK '{print $0}' *.txt
— licznik czasu

7
Ma to wyraźną wadę polegającą na tym, że na końcu (od pierwszej możliwości) lub na początku (druga alternatywa) będą puste linie. Możesz jednak łatwo ustrzec się przed tym, używając awk 'FNR==1 && NR > 1 ...'zamiast tego.
— tripleee

5
Jeśli umieścisz >finalfile.txtpo done, możesz nadpisać zamiast dołączać, co usunie wymóg upewnienia się, że przed pętlą brakuje pliku lub jest on pusty.
— tripleee

53

Jeśli masz wystarczająco dużo plików, które możesz wyświetlić każdy z nich, możesz użyć podstawiania procesów w Bash, wstawiając nowy wiersz między każdą parą plików:

cat File1.txt <(echo) File2.txt <(echo) File3.txt > finalfile.txt

1
Piękny! Dzięki.
— Bob Kocisko

Pomogło mi to w przypadku moich certyfikatów Letsencrypt do tworzenia plików .pem.
— leeman24

35

Gdybym to robił, użyłbym seda:

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

W tym wzorcu sed $ ma dwa znaczenia, po pierwsze dopasowuje tylko numer ostatniej linii (jako zakres linii do zastosowania wzorca), a po drugie dopasowuje koniec linii we wzorcu podstawiania.

Jeśli twoja wersja seda nie ma -s(przetwarzaj pliki wejściowe osobno), możesz to wszystko zrobić w pętli:

for f in *.txt ; do sed -e '$s/$/\n/' $f ; done > finalfile.txt

3
Lub w GNU sed:sed -s '$G' *.txt > finalfile.txt
— Ruud Helderman

Tylko jeden strumień! to powinna być zaakceptowana odpowiedź!
— Yassine ElBadaoui

uważajcie ludzie, właśnie zawiesiłem komputer, ponieważ użyłem go findzamiast *.txt, co oznaczało, że plik został dołączony do siebie!
— Xerus

11

Możesz to zrobić używając, xargsjeśli chcesz, ale główna idea jest taka sama:

find *.txt | xargs -I{} sh -c "cat {}; echo ''" > finalfile.txt

1
Dzięki. Uważam, że jest xargsdużo łatwiejszy w użyciu niż pętle w bashu.
— RawwrBag

9

Działa to w Bash:

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

W przeciwieństwie do odpowiedzi z >>(dołącz), dane wyjściowe tego polecenia mogą być przesłane potokiem do innych programów.

Przykłady:

  • for f in File*.txt; do cat $f; echo; done > finalfile.txt
  • (for ... done) > finalfile.txt (pareny są opcjonalne)
  • for ... done | less (rury w mniej)
  • for ... done | head -n -1 (to usuwa końcową pustą linię)

7

Tak właśnie zrobiłem to na OsX 10.10.3

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

ponieważ proste polecenie „echo” bez parametrów zakończyło się brakiem wstawienia nowych wierszy.


Spowoduje to umieszczenie ciągu na końcu pliku; jak wstawić go między każdy plik?
— onassar

3

W Pythonie łączy się to z pustymi wierszami między plikami ( ,zapobiega dodawaniu dodatkowego końcowego pustego wiersza):

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

Oto brzydka jedna linijka Pythona, którą można wywołać z powłoki i wypisuje dane wyjściowe do pliku:

python -c "from sys import argv; print '\n'.join(open(f).read() for f in argv[1:])," File*.txt > finalfile.txt
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.