Hapus karakter baris baru setiap N baris

16

Memproses teks, saya harus menghapus karakter baris baru setiap dua baris.

Contoh teks:

this is line one
and this is line two
the third and the
fourth must be pasted too

Output yang diinginkan:

this is line one and this is line two
the third and the fourth must be pasted too

Saya mencoba whileloop, tetapi loop sementara adalah praktik buruk. Apakah mungkin untuk melakukannya menggunakan trperintah lain?

Tomaweb
sumber
4
Judul mengatakan "setiap N baris", tetapi dalam pertanyaan dan contoh itu "setiap 2 baris". Sebagian besar jawaban hanya berfungsi untuk N = 2. Apakah Anda mencari sesuatu yang bekerja untuk semua N?
JigglyNaga
Itulah kuncinya. Semua orang menjawab untuk 2 baris tetapi saya harus menggunakan N = 3 atau N = 4
jomaweb

Jawaban:

24

paste(juga utilitas sederhana POSIX standar tr) adalah alat Anda untuk itu.

Dengan asumsi Anda ingin karakter baris baru diganti dengan spasi alih-alih hanya dihapus seperti pada sampel Anda:

paste -d ' ' - - < file

Atau:

paste -sd ' \n' file

Ganti ' 'dengan '\0'jika Anda memang ingin mereka dihapus.

Untuk mengganti 2 dari 3:

paste -sd '  \n' file

1 dari 3, dimulai dengan yang kedua:

paste -sd '\n \n' file

Dan seterusnya.

Hal baik lainnya pasteadalah bahwa ia tidak akan meninggalkan garis tanpa putus. Misalnya, jika Anda menghapus setiap baris baru dalam file (seperti dengan tr -d '\n' < fileatau tr '\n' ' ' < file), Anda berakhir tanpa baris sama sekali karena baris harus diakhiri dengan karakter baris baru. Jadi, biasanya lebih baik menggunakan pasteuntuk itu (seperti dalam paste -sd '\0' fileatau paste -sd ' ' file) yang akan menambahkan karakter garis baru yang diperlukan untuk memiliki teks yang valid.

Stéphane Chazelas
sumber
11

Dengan sed GNU modern

sed -rz 's/\n([^\n]*\n)/ \1/g' sample.text

Dan awk

awk '{getline line2;print $0, line2}' sample.text
Costas
sumber
3
Itu sedpendekatan cara menyeruput seluruh file dalam memori (asalkan tidak mengandung NUL byte) dan melakukan beberapa substitusi regexp mahal. Saya tidak bisa melihat manfaatnya dari sed 'N;s/\n/ /'pendekatan standar .
Stéphane Chazelas
6

Gunakan seduntuk ini seperti yang ditunjukkan di bawah ini:

SHW@SHW:/tmp $ cat a
this is line one
and this is line two
the third and the
fourth must be pasted too

SHW@SHW:/tmp $ sed 'N;s/\n/ /' a -i

SHW@SHW:/tmp $ cat a
this is line one and this is line two
the third and the fourth must be pasted too
SHW
sumber
4

Cara lain adalah dengan menggunakan xargs:

$ < txt xargs -d '\n' -n 2 echo
this is line one and this is line two
the third and the fourth must be pasted too

dimana

$ cat txt
this is line one
and this is line two
the third and the
fourth must be pasted too

Meskipun, solusi ini cukup berlebihan karena echoproses dieksekusi untuk setiap baris ... Jadi, selain contoh mainan, solusi berdasarkan awk / sed atau serupa harus lebih disukai.

maxschlepzig
sumber
1
Tergantung pada echoimplementasi Anda, Anda juga akan memiliki masalah dengan karakter backslash atau beberapa baris yang dimulai dengan -(suka --helpatau -nenedengan GNU echo). Perhatikan juga bahwa itu -dadalah ekstensi GNU.
Stéphane Chazelas
Untuk menghindari masalah dengan echo, Anda dapat menggunakan ini:< txt xargs -d '\n' -n 2 printf -- '%s %s\n'
nyuszika7h
4

Ini sebenarnya sangat sederhana di vim. Untuk bergabung dengan setiap baris gunakan Jperintah, lalu gunakan %normperintah untuk menerapkannya ke setiap baris secara bersamaan. Sebagai contoh

:%norm J<CR>

(Kalau-kalau Anda tidak terbiasa dengan vim, <CR>cukup masukkan saja)

Ini bahkan berfungsi untuk bergabung dengan sejumlah garis acak. Misalnya, untuk bergabung setiap sepuluh baris akan

:%norm 9J<CR>

Jika Anda merasa tidak nyaman dengan vim, dan Anda lebih suka menggunakannya sebagai alat baris perintah, daripada editor teks interaktif, Anda bisa melakukannya:

vim myfile -c '%norm J' -c 'wq'
DJMcMayhem
sumber
Apakah downvoter mau menjelaskan apa yang dapat saya lakukan untuk meningkatkan jawaban ini?
DJMcMayhem
3
$ awk '{printf "%s%s",$0,(NR%2?" ":"\n")}' sample.txt
this is line one and this is line two
the third and the fourth must be pasted too

Ini mencetak setiap baris,, $0diikuti oleh spasi atau baris baru tergantung pada apakah nomor baris NR,, ganjil atau genap.

Ekspresi NR%2?" ":"\n"adalah pernyataan terner. Ekspresi NR%2bernilai true (bukan nol) jika nomor barisnya ganjil. Dalam kasus ini, ekspresi ternary mengembalikan spasi. Jika itu bernilai false (nol), maka baris baru dikembalikan.

Alternatif

Seperti yang disarankan oleh Costas di komentar:

$ awk '{ORS=(NR%2?" ":RS)}1' sample.txt
this is line one and this is line two
the third and the fourth must be pasted too

Di sini, pernyataan ternary NR%2?" ":RSdigunakan untuk mengembalikan spasi atau pemisah rekaman input ( RS, default = baris baru). Nilai ini ditugaskan untuk pemisah catatan keluaran ORS,. Di 1akhir perintah adalah singkatan cryptic awk untuk print-the-record.

John1024
sumber
Anda masih dapat menyimpan 3 karakter: ()tanda kurung dan spasi setelah printf;)
maxschlepzig
1
Ternary? Oh! 'NR%2{printf("%s ",$0);next}1'
Costas
Dengan jawaban maxschlepzig dan pernyataan ternary:'{ORS=(NR%2?" ":RS)}1'
Costas
@Costas saya suka itu. Jawaban diperbarui dengan ORSsolusi.
John1024
2

Solusi generik, ganti 5dengan jumlah garis yang dibutuhkan

$ # eof to ensure last line has newline ending
$ seq 16 | perl -pe 's/\n/ / if ++$i%5 && !eof'
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16

$ # or just use pr
$ seq 16 | pr -5ats' '
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16
Sundeep
sumber
1

Anda dapat menggunakan awkini:

$ awk '{c="\n"} NR%2 {c=" "} { printf("%s%s", $0, c) } ' txt

Itu menghasilkan:

this is line one and this is line two
the third and the fourth must be pasted too

dimana:

$ cat txt
this is line one
and this is line two
the third and the
fourth must be pasted too

The awktindakan dijalankan untuk setiap baris, variabel khusus $0referensi baris saat ini, NRadalah nomor baris saat ini (mulai dari 1). Tindakan kedua dijaga oleh ekspresi NR%2, yang merupakan operasi modulo. Dengan demikian, c=" "hanya dieksekusi jika NR%2benar, yaitu untuk nomor garis ganjil.

The awksintaks C seperti, tapi beberapa elemen adalah opsional dalam beberapa konteks - misalnya titik koma.

maxschlepzig
sumber
cVariabel Anda adalah ORS:'NR%2{ORS=" "}1;{ORS=RS}'
Costas
0

Menggunakan ed:

$ cat text
this is line one
and this is line two
the third and the
fourth must be pasted too
this is line one
and this is line two
the third and the
fourth must be pasted too

$ ed text <<'END_ED'
g/./s/$/ /\
j
w text.new
END_ED
164
164

$ cat text.new
this is line one and this is line two
the third and the fourth must be pasted too
this is line one and this is line two
the third and the fourth must be pasted too

The edperintah mengedit akan, untuk setiap baris ( gberlaku satu set mengedit perintah untuk setiap baris yang cocok ekspresi reguler yang diberikan), menambahkan karakter ruang untuk akhir dan bergabung dengan baris berikutnya. Kemudian ia menulis teks yang dihasilkan ke file bernama text.new.

Kusalananda
sumber
0

Dengan Ruby.

Saya berasumsi setiap blok ngaris harus digabungkan. Misalkan n = 3, file input adalah 'infile'dan hasilnya ditulis ke file 'outfile'.

Bangun file

Ruby -e "File.write 'infile', <<_
> Line 1
> Line 2
> Line 3
> Line 4
> Line 5
> Line 6
> Line 7
> _"

Konfirmasikan konten file

ruby -e "p File.read 'infile'"
  # "Line 1\nLine 2\nLine 3\nLine 4\nLine 5\nLine 6\nLine 7\n"

Hapus baris baru dan tulis ke file

ruby -e "File.write 'outfile', File.readlines('infile').
  each_with_index { |line,i| line.chomp! unless (i+1)%3==0 }"

Konfirmasikan konten

ruby -e "puts File.read 'outfile'"
  # ["Line 1", "Line 2", "Line 3\n", "Line 4", "Line 5", "Line 6\n", "Line 7"]
Cary Swoveland
sumber
1
Bagus Secara teori, di rubyluar topik tentang U&L. Tapi, karena Anda menggunakannya dari baris perintah dengan ruby -e, itu membuatnya cukup pada topik.
grochmal