Menggabungkan banyak file dengan header yang sama

26

Saya memiliki beberapa file dengan header yang sama dan vektor yang berbeda di bawahnya. Saya perlu menyatukan semuanya tetapi saya hanya ingin header file pertama yang akan digabungkan dan saya tidak ingin header lain digabungkan karena semuanya sama.

misalnya: file1.txt

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

file2.txt

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

Saya perlu hasilnya

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

Saya bisa menulis skrip dalam R tetapi saya membutuhkannya di shell?

Jana
sumber

Jawaban:

17

Jika Anda tahu bagaimana melakukannya di R, maka tentu saja melakukannya dalam R. Dengan alat unix klasik, ini paling alami dilakukan dalam awk.

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

Baris pertama skrip awk cocok dengan baris pertama file ( FNR==1) kecuali jika juga baris pertama di semua file ( NR==1). Ketika kondisi ini terpenuhi, ekspresi while (/^<header>/) getline;dieksekusi, yang menyebabkan awk untuk terus membaca baris lain (melewatkan yang sekarang) selama yang saat ini cocok dengan regexp ^<header>. Baris kedua skrip awk mencetak semuanya kecuali untuk baris yang sebelumnya dilewati.

Gilles 'SANGAT berhenti menjadi jahat'
sumber
Terima kasih Gilles. Setiap file saya dalam GB. R tidak akan efisien melakukan ini. Itulah mengapa saya bertanya.
Jana
@Jana Apakah ada baris yang terlihat seperti header tetapi tidak di bagian atas file? Jika tidak, cara tercepat adalah menggunakan grep(seperti dalam jawaban sputnik ).
Gilles 'SANGAT berhenti menjadi jahat'
Tidak ada baris tajuk yang serupa dengan semua file dan hanya di bagian atas setiap file. Ya, grep lebih cepat. Terima kasih Anda berdua
Jana
1
@Jana Ngomong-ngomong, jika semua file Anda memiliki jumlah baris header yang sama, inilah cara lain (yang saya perkirakan lebih cepat): head -n 10 file1.txt >output.txt && tail -q -n +11 file*.txt >>output.txt(jika Anda memiliki 10 baris header). Juga, jika file Anda memiliki angka dalam namanya, waspadalah yang file9.txtdiurutkan antara file89.txtdan file90.txt. Jika file Anda telah nomor suka file001.txt, ..., files009.txt, files010.txt, ..., maka files*.txtakan daftar mereka dalam urutan yang benar.
Gilles 'SANGAT berhenti menjadi jahat'
Solusi yang lebih baik (dari stackoverflow.com/a/16890695/310441 ) yang tidak memerlukan pencocokan regex: awk 'FNR==1 && NR!=1{next;}{print}' *.csv
Owen
42

Solusi lain, mirip dengan " cat+grep" dari atas, menggunakan taildan head:

  1. Tulis header file pertama ke dalam output:

    head -2 file1.txt > all.txt

    - head -2mendapat 2 baris pertama file.

  2. Tambahkan konten semua file:

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

    - -n +3membuat tailgaris-garis cetak dari 3 ke ujung, -qmemberi tahu untuk tidak mencetak header dengan nama file (baca man), >>menambah file, tidak menimpa sebagai >.

Dan tentu saja Anda dapat menempatkan kedua perintah dalam satu baris:

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

atau alih-alih ;menempatkan di &&antara mereka untuk pemeriksaan sukses.

xealits
sumber
3
Saya sarankan untuk lebih lanjut hanya ke: (head -2 file1.txt ; tail -n +3 -q file*.txt ) > all.txtatau(head -2 file1.txt && tail -n +3 -q file*.txt ) > all.txt
HongboZhu
4

Coba lakukan ini:

$ 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

CATATAN

  • yang -vberarti bendera untuk membalikkan pertandingan
  • ^dalam REGEX , berarti awal dari string
  • jika Anda memiliki banyak file, Anda dapat melakukannya

:

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

Ini adalah teknik mengiris array .

Gilles Quenot
sumber
Terima kasih sputnick, Tapi saya punya ~ 30 file (file1.txt, file2.txt, file3.txt..filen.txt) untuk digabungkan. Haruskah saya mengetik setiap nama file atau apakah ada cara lain untuk melakukannya?
Jana
Lihat posting saya yang diedit dengan teknik mengiris
Gilles Quenot
Ini menghapus <header>baris di mana saja di file, bukan hanya di awal. Ini mungkin bukan masalah di sini, tergantung data.
Gilles 'SANGAT berhenti menjadi jahat'
1
Simpler:grep '^<header>' file1.txt >output.txt && grep -v '^<header>' file*.txt >>output.txt
Gilles 'SO- stop being evil'
@Gilles: Saya perhatikan jawaban Anda setelah waktu yang lama tetapi itu sangat berguna
Jana
1

The tailperintah (pada GNU, setidaknya) memiliki opsi untuk melewatkan sejumlah tertentu garis awal. Untuk mencetak dari baris kedua dan seterusnya, yaitu melewati header satu baris, lakukan:tail -n+2 myfile

Jadi, untuk menjaga header dua baris dari file pertama tetapi bukan yang kedua, di Bash:

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

Atau, untuk banyak file:

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

Jika string tertentu diketahui ada di semua baris header tetapi tidak pernah di sisa file input, grep -vadalah pendekatan yang lebih sederhana, seperti yang ditunjukkan sputnik.

etal
sumber
1

Lebih pendek (tidak harus lebih cepat) dengan sed:

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

Ini akan menghapus semua baris yang dimulai dengan <header>...mulai dari baris 3, sehingga header pertama dipertahankan dan header lainnya dihapus. Jika ada jumlah baris yang berbeda di header, sesuaikan perintah (mis. Untuk penggunaan header 6-baris 7alih-alih 3).
Jika jumlah baris di header tidak diketahui, Anda dapat mencoba seperti ini:

sed '1{
: again
n
/^<header>/b again
}
/^<header>/d
' file*.txt > all.txt
don_crissti
sumber
0

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

Dengan asumsi Anda menggunakan folder dengan file .txt dengan header yang sama yang perlu digabungkan / digabungkan, kode ini akan menggabungkan semua file txt menjadi all.txt hanya dengan satu header. baris pertama (baris dipisahkan oleh titik koma) mengumpulkan semua file teks untuk digabungkan, baris kedua menampilkan header dari file txt pertama ke all.txt , dan baris terakhir menggabungkan semua file teks yang dikumpulkan tanpa header (dengan memulai Rangkaian dari baris 2 dan seterusnya) dan menambahkan ke all.txt .

Eric
sumber
sedikit penjelasan akan sangat membantu para pengguna di masa depan
Jeff Schaller