Łą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.