Bisakah sed ganti karakter baris baru?


43

Apakah ada masalah dengan karakter baris sed dan baru?
Saya punya file test.txt dengan konten berikut

aaaaa  
bbbbb  
ccccc  
ddddd  

Berikut ini tidak berfungsi:
sed -r -i 's/\n/,/g' test.txt

Saya tahu bahwa saya dapat menggunakan trini tetapi pertanyaan saya adalah mengapa sepertinya tidak mungkin dengan sed.

Jika ini adalah efek samping dari pemrosesan file baris demi baris saya akan tertarik mengapa ini terjadi. Saya pikir grepmenghapus baris baru. Apakah sed melakukan hal yang sama?


1
Dalam hal ini, sed mungkin bukan alat terbaik untuk digunakan (mis. "Tr"). Ada alat yang lebih intuitif, lebih mudah dibaca / dirawat, berkinerja lebih baik (terutama pada data besar) dll. ... Jangan gunakan palu Anda untuk memasukkan sekrup (bahkan jika itu berfungsi). Anda dapat menemukan perbandingan di: http://slash4.de/blog/python/sed-replace-newline-or-python-awk-tr-perl-xargs.html
omoser

2
trakan menambahkan trailing ,dan akan menampilkan garis yang tidak tertentu. Yang terbaik adalah menggunakan paste:paste -sd , test.txt
Stéphane Chazelas

Jawaban:


49

Dengan GNU seddan yang disediakan POSIXLY_CORRECTtidak di lingkungan (untuk input single-line):

sed -i ':a;N;$!ba;s/\n/,/g' test.txt

Dari https://stackoverflow.com/questions/1251999/sed-how-can-i-replace-a-newline-n :

  1. buat label via :a
  2. tambahkan baris saat ini dan berikutnya ke ruang pola via N
  3. jika kita sebelum baris terakhir, cabang ke label yang dibuat $!ba( $!berarti tidak melakukannya di baris terakhir (karena harus ada satu baris terakhir)).
  4. akhirnya substitusi mengganti setiap baris baru dengan koma pada ruang pola (yang merupakan keseluruhan file).

Ini sepertinya menunjukkan bahwa masalahnya adalah sed membaca baris per baris. Tapi saya tidak mengerti mengapa ini menjadi masalah. Itu hanya bisa membaca baris dan mengganti karakter baris baru (atau karakter terakhir) dengan,
Jim

1
@ Jim sepertinya tidak ada dalam buffer untuk dicocokkan, tapi aku tidak fasih dengan sed, mungkin orang lain bisa menjelaskan hal itu. Saya pikir Anda harus memperpanjang Q Anda dengan info spesifik itu, sehingga orang lebih cenderung membacanya, dan mudah-mudahan menjawab.
Anthon

Ini menghasilkanba: Event not found
krb686

@ krb686 Apa "Ini" yang Anda maksud? Apakah Anda menjalankan sedperintah di atas dengan opsi yang tepat? Pada test.txt file apa ? Dengan versi sed(coba sed --version) yang mana?
Anthon

@Anthon Maaf, saya pikir saya bermaksud mengatakan "the". Saya membaca posting SO lainnya yang memberi tahu saya bahwa csh mengharuskan saya melarikan diri !. Menariknya, itu masih tidak berhasil untuk saya dan saya akhirnya harus meloloskan diri dari naskah !saya .csh. Jadi saya tidak benar-benar memiliki masalah saat ini, tetapi Anda tahu mengapa itu terjadi? Apa yang berhasil untuk saya adalahsed :a;N;$\\!ba;s/\n/ /g'
krb686

17

Ini bekerja dengan GNU sed:

sed -z 's/\n/,/g' 

-z sudah termasuk sejak 4.2.2

NB. -zmengubah pembatas menjadi karakter nol ( \0). Jika input Anda tidak mengandung karakter nol, seluruh input diperlakukan sebagai satu baris. Ini bisa datang dengan keterbatasannya .

Untuk menghindari penggantian baris baru dari baris terakhir, Anda dapat mengubahnya kembali:

sed -z 's/\n/,/g;s/,$/\n/'

(Yang merupakan sedsintaksis GNU lagi, tetapi tidak masalah karena semuanya hanya GNU)


3
Ini juga akan menggantikan baris baru yang mungkin bukan yang diinginkan OP ... bandingkan hasilnya dengan solusi mikeserv .
don_crissti

7

Dari situs web Oracle:

Utilitas sed bekerja dengan secara berurutan membaca file, baris demi baris, ke dalam memori. Ini kemudian melakukan semua tindakan yang ditentukan untuk saluran dan menempatkan garis kembali dalam memori untuk dibuang ke terminal dengan perubahan yang diminta dibuat. Setelah semua tindakan terjadi pada baris yang satu ini, ia membaca baris file berikutnya dan mengulangi prosesnya sampai selesai dengan file tersebut.

Pada dasarnya ini berarti bahwa karena sed membaca baris demi baris, karakter baris baru tidak cocok.

Solusi dari https://stackoverflow.com/questions/1251999/sed-how-can-i-replace-a-newline-n adalah:

sed ':a;N;$!ba;s/\n/,/g'

atau, dalam versi portabel (tanpa ;menggabungkan setelah label tanda melompat)

sed -e ':a' -e 'N;$!ba' -e 's/\n/,/g'

Penjelasan tentang cara kerjanya disediakan pada halaman itu.


Saya menggunakan bentuk modifikasi ini untuk mengurai log VPN dan menempatkan pengguna "dikonfirmasi" dan informasi cap waktu pada baris yang sama. Tepuk tangan!
user208145

Perhatikan bahwa sintaksinya spesifik untuk GNU, dan bahkan dengan GNU sed, jika POSIXLY_CORRECT berada di lingkungan dan input hanya memiliki satu baris, tidak akan ada output.
Stéphane Chazelas

5

sedselalu menghapus garis akhir trailing \ntepat sebelum mengisi ruang pola, dan kemudian menambahkan satu sebelum menuliskan hasil skripnya. Sebuah \newline dapat dimiliki dalam pola-ruang dengan berbagai cara - tetapi tidak pernah jika itu bukan hasil edit. Ini penting - \ngaris utama dalam sedruang pola selalu mencerminkan perubahan, dan tidak pernah terjadi di aliran input. \newlines adalah satu-satunya pembatas yang seddapat diandalkan oleh der dengan input yang tidak diketahui.

Jika Anda ingin mengganti semua \newline dengan koma dan file Anda tidak terlalu besar, maka Anda dapat melakukannya:

sed 'H;1h;$!d;x;y/\n/,/'

Itu menambahkan setiap baris input ke hruang lama - kecuali yang pertama, yang alih-alih menimpa hruang lama - mengikuti \nkarakter ewline. Kemudian dmenghapus setiap baris bukan yang $!terakhir dari output. Pada baris terakhir H, ruang lama dan pola xdiubah dan semua \nkarakter ewline y///diterjemahkan ke koma.

Untuk file besar hal semacam ini pasti akan menyebabkan masalah - sedbuffer pada batas-garis, yang dapat dengan mudah dipenuhi dengan tindakan semacam ini.


2

Atau, Anda dapat menggunakan sintaks yang sedikit lebih sederhana:

sed ':a;N;s/\n/,/g;ba'

... hanya mengubah urutan urutan.


3
Tetapi jalankan sperintah untuk setiap jalur input pada ruang pola yang semakin besar.
Stéphane Chazelas

1

Ada beberapa sihir sed yang sangat bagus di sini. Dan beberapa poin bagus tentang ruang pola meluap. Saya suka menggunakan sed bahkan ketika itu bukan cara yang paling sederhana, karena sangat kompak dan kuat. Namun memiliki keterbatasan, dan untuk sejumlah besar data, ruang pola harus mahoosive.

GNU mengatakan ini:

Bagi mereka yang ingin menulis skrip sed portabel, perlu diketahui bahwa beberapa implementasi telah diketahui membatasi panjang garis (untuk pola dan ruang pegang) tidak lebih dari 4000 byte. Standar posix menentukan bahwa implementasi sed yang sesuai harus mendukung setidaknya 8192 byte panjang garis. GNU sed tidak memiliki batas bawaan pada panjang garis; selama itu dapat malloc () lebih banyak (virtual) memori, Anda dapat memberi makan atau membangun garis selama Anda suka.
Namun, rekursi digunakan untuk menangani sub-pola dan pengulangan yang tidak terbatas. Ini berarti bahwa ruang stack yang tersedia dapat membatasi ukuran buffer yang dapat diproses oleh pola tertentu.

Saya tidak punya banyak untuk ditambahkan, tapi saya ingin mengarahkan Anda ke panduan masuk saya untuk sed . Ini luar biasa. http://www.grymoire.com/Unix/Sed.html

dan inilah solusi saya:

for i in $(cat test.txt); do echo -n $i','; done; echo '' >> somewhere

baik itu berhasil



-1

Katakanlah Anda ingin mengganti baris baru dengan \n. Saya ingin melakukan itu, jadi inilah yang saya lakukan:

(echo foo; echo bar; echo baz) | sed -r '$!s/$/\\n/' | tr -d '\n' 
# Output: foo\nbar\nbaz

Inilah fungsinya: untuk semua baris kecuali yang terakhir , tambahkan \n. Lalu, hapus baris baru dengan tr.


-rhanya tersedia di GNU sed, bukan BSD.
kenorb
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.