Połącz wiele plików z tym samym nagłówkiem

26

Mam wiele plików z tym samym nagłówkiem i różnymi wektorami poniżej. Muszę połączyć je wszystkie, ale chcę, aby tylko nagłówek pierwszego pliku był konkatenowany i nie chcę, aby inne nagłówki były konkatenowane, ponieważ wszystkie są takie same.

na przykład: plik1.txt

<header>INFO=<ID=DP,Number=1,Type=Integer>
<header>INFO=<ID=DP4,Number=4,Type=Integer>
A
B 
C

plik2.txt

<header>INFO=<ID=DP,Number=1,Type=Integer>
<header>INFO=<ID=DP4,Number=4,Type=Integer>
D
E 
F

Potrzebuję wyjścia

<header>INFO=<ID=DP,Number=1,Type=Integer>
<header>INFO=<ID=DP4,Number=4,Type=Integer>
A
B
C
D
E 
F

Mógłbym napisać skrypt w R, ale potrzebuję go w powłoce?

Jana
źródło

Odpowiedzi:

17

Jeśli wiesz, jak to zrobić w R, to na pewno zrób to w R. W klasycznych narzędziach unixowych jest to najbardziej naturalnie wykonywane w awk.

awk '
    FNR==1 && NR!=1 { while (/^<header>/) getline; }
    1 {print}
' file*.txt >all.txt

Pierwszy wiersz skryptu awk pasuje do pierwszego wiersza pliku ( FNR==1), chyba że jest to również pierwszy wiersz we wszystkich plikach ( NR==1). Gdy te warunki są spełnione, wyrażenie while (/^<header>/) getline;jest wykonywane, co powoduje, że awk kontynuuje czytanie innej linii (pomijając bieżącą), o ile bieżąca pasuje do wyrażenia regularnego ^<header>. Druga linia skryptu awk drukuje wszystko oprócz linii, które zostały wcześniej pominięte.

Gilles „SO- przestań być zły”
źródło
Dzięki Gilles. Każdy z moich plików jest w GB. R nie będzie efektywny, zrób to. Dlatego spytałem.
Jana
@Jana Czy są linie, które wyglądają jak nagłówki, ale nie znajdują się na górze pliku? Jeśli nie, najszybszym sposobem jest użycie grep(jak w odpowiedzi sputnika ).
Gilles „SO- przestań być zły”
Nie, linie nagłówków są podobne do wszystkich plików i znajdują się tylko na górze każdego pliku. Tak grep był szybszy. Dziękuję wam obojgu
Jana
1
@Jana Przy okazji, jeśli wszystkie twoje pliki mają taką samą liczbę linii nagłówka, oto inny sposób (który, jak sądzę, będzie jeszcze szybszy): head -n 10 file1.txt >output.txt && tail -q -n +11 file*.txt >>output.txt(jeśli masz 10 linii nagłówka). Ponadto, jeśli twoje pliki mają numery w nazwach, strzeż się, że file9.txtsą posortowane między file89.txta file90.txt. Jeśli pliki zostały numery podoba file001.txt, ... files009.txt, files010.txt..., a następnie files*.txtwyświetli je w odpowiedniej kolejności.
Gilles „SO- przestań być zły”
Lepsze rozwiązanie (z stackoverflow.com/a/16890695/310441 ), które nie wymaga dopasowania wyrażenia regularnego: awk 'FNR==1 && NR!=1{next;}{print}' *.csv
Owen
42

Inne rozwiązanie, podobne do „ cat+grep” z góry, przy użyciu taili head:

  1. Zapisz nagłówek pierwszego pliku w pliku wyjściowym:

    head -2 file1.txt > all.txt

    - head -2pobiera 2 pierwsze linie pliku.

  2. Dodaj zawartość wszystkich plików:

    tail -n +3 -q file*.txt >> all.txt

    - -n +3wykonuje taillinie wydruku od 3 do końca, -qmówi, aby nie drukował nagłówka z nazwą pliku (odczyt man), >>dodaje do pliku, nie zastępuje go jako >.

I upewnij się, że możesz umieścić oba polecenia w jednym wierszu:

head -2 file1.txt > all.txt; tail -n +3 -q file*.txt >> all.txt

lub zamiast ;umieszczać &&między nimi w celu sprawdzenia sukcesu.

xealits
źródło
3
Sugeruję dalej po prostu: (head -2 file1.txt ; tail -n +3 -q file*.txt ) > all.txtlub(head -2 file1.txt && tail -n +3 -q file*.txt ) > all.txt
HongboZhu,
4

Spróbuj to zrobić:

$ cat file1.txt; grep -v "^<header" file2.txt
<header>INFO=<ID=DP,Number=1,Type=Integer>
<header>INFO=<ID=DP4,Number=4,Type=Integer>
A
B 
C
D
E 
F

UWAGA

  • te -vśrodki flag odwrócić mecz
  • ^w REGEX oznacza początek łańcucha
  • jeśli masz kilka plików, możesz to zrobić

:

array=( files*.txt )
{ cat ${array[@]:0:1}; grep -v "^<header" ${array[@]:1}; } > new_file.txt

To technika wycinania tablic .

Gilles Quenot
źródło
Dzięki sputnick, ale mam ~ 30 plików (plik1.txt, plik2.txt, plik3.txt..filen.txt) do połączenia. Czy powinienem wpisać każdą nazwę pliku, czy istnieją inne sposoby?
Jana
Zobacz mój edytowany post z techniką krojenia
Gilles Quenot,
To usuwa <header>linie w dowolnym miejscu w pliku, nie tylko na początku. W zależności od danych może to nie stanowić problemu.
Gilles „SO- przestań być zły”
1
Prostsze:grep '^<header>' file1.txt >output.txt && grep -v '^<header>' file*.txt >>output.txt
Gilles 'SO- przestań być zły'
@Gilles: Po długim czasie zauważyłem twoją odpowiedź, ale była bardzo przydatna
Jana
1

The tailPoleceń (GNU przynajmniej) ma możliwość pominięcia określonej liczby pierwszych linii. Aby wydrukować od drugiej linii, tj. Pominąć nagłówek jednowierszowy, wykonaj:tail -n+2 myfile

Aby zachować dwuwierszowy nagłówek pierwszego pliku, ale nie drugiego, w Bash:

cat file1.txt <(tail -n+3 file2.txt) > combined.txt

Lub w przypadku wielu plików:

head -n1 file1.txt > combined.txt
for fname in *.txt
do
    tail -n+3 $fname >> combined.txt
done

Jeśli wiadomo, że określony ciąg występuje we wszystkich wierszach nagłówka, ale nigdy w pozostałych plikach wejściowych, grep -vjest to prostsze podejście, jak pokazał sputnik.

etal
źródło
1

Krótszy (niekoniecznie szybszy) z sed:

sed -e '3,${/^<header>/d' -e '}' file*.txt > all.txt

Spowoduje to usunięcie wszystkich linii <header>...zaczynających się od linii 3, więc pierwszy nagłówek zostanie zachowany, a pozostałe nagłówki zostaną usunięte. Jeśli w nagłówku jest inna liczba wierszy, odpowiednio dostosuj polecenie (np. 7Zamiast nagłówka użyj 6 wierszy 3).
Jeśli liczba wierszy w nagłówku jest nieznana, możesz spróbować w ten sposób:

sed '1{
: again
n
/^<header>/b again
}
/^<header>/d
' file*.txt > all.txt
don_crissti
źródło
0

array = (* .txt); head -1 $ {array [0]}> all.txt; tail -n +2 -q $ {array [@]: 0} >> all.txt

Zakładając, że używasz folderu z plikami .txt z tym samym nagłówkiem, który wymaga połączenia / konkatenacji, ten kod połączyłby pliki txt w plik all.txt z jednym nagłówkiem. pierwszy wiersz (linie oddzielone średnikami) zbiera wszystkie pliki tekstowe do konkatenacji, drugie linie generują nagłówek z pierwszego pliku txt do all.txt , a ostatni wiersz konkatenuje wszystkie pliki tekstowe zebrane bez nagłówka (uruchamiając konkatenacja od drugiego rzędu) i dołącza ją do pliku all.txt .

Eric
źródło
małe wyjaśnienie może pomóc w przyszłości użytkownikom
Jeff Schaller