Bagaimana saya bisa mengganti baris baru (\ n) menggunakan sed?


1371

Bagaimana saya bisa mengganti baris baru (" \n") dengan spasi (" ") menggunakan sedperintah?

Saya gagal mencoba:

sed 's#\n# #g' file
sed 's#^$# #g' file

Bagaimana saya memperbaikinya?


27
trhanya alat yang tepat untuk pekerjaan itu jika mengganti satu karakter untuk satu karakter, sedangkan contoh di atas menunjukkan ganti baris baru dengan spasi .. Jadi dalam contoh di atas, tr bisa bekerja .. Tetapi akan membatasi nanti.
Marah 84

9
trdalam alat yang tepat untuk pekerjaan itu karena si penanya ingin mengganti setiap baris baru dengan spasi, seperti yang ditunjukkan dalam contohnya. Penggantian baris baru unik untuk sedtetapi mudah dilakukan oleh tr. Ini pertanyaan umum. Melakukan penggantian regex tidak dilakukan dengan trtetapi oleh sed, yang akan menjadi alat yang tepat ... untuk pertanyaan yang berbeda.
Mike S

3
"tr" juga dapat menghapus baris baru `tr -d '\ n'` namun Anda juga mungkin ingin menghapus pengembalian menjadi lebih universal `tr -d '\ 012 \ 015'`.
anthony

2
PERINGATAN: "tr" bertindak berbeda sehubungan dengan rentang karakter antara Linux dan mesin Solaris yang lebih lama (EG sol5.8). EG: `tr -d 'az'` dan `tr -d '[az]'`. Untuk itu saya sarankan Anda menggunakan "sed" yang tidak memiliki perbedaan itu.
anthony

2
@ Mike Terima kasih atas jawabannya. Ikuti tr '\012' ' 'dengan echo. Kalau tidak, baris baris terakhir dalam file juga dihapus. tr '\012' ' ' < filename; echolakukan triknya.
Bernie Reiter

Jawaban:


1514

Gunakan solusi ini dengan GNU sed:

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

Ini akan membaca seluruh file dalam satu lingkaran, kemudian mengganti baris baru dengan spasi.

Penjelasan:

  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 spasi di ruang pola (yang merupakan seluruh file).

Berikut ini adalah sintaks yang kompatibel lintas platform yang bekerja dengan BSD dan OS X sed(sesuai komentar @Benjie ):

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

Seperti yang Anda lihat, menggunakan seduntuk masalah sederhana jika tidak bermasalah. Untuk solusi yang lebih sederhana dan memadai lihat jawaban ini .


45
@Arjan dan Masi: OS X menggunakan BSD seddaripada GNU sed, jadi mungkin ada beberapa perbedaan yang halus (dan beberapa tidak begitu halus) di keduanya. Ini adalah rasa sakit yang konstan jika Anda bekerja pada mesin OS X dan * nix. Saya biasanya menginstal GNU coreutilsdan findutilsOS X, dan mengabaikan versi BSD.
Telemakus

50
Ini :abukan register, ini label cabang. Ini adalah target untuk bperintah * yang berfungsi seperti "goto". Menyebutnya register berarti Anda dapat membuat lokasi penyimpanan. Hanya ada dua "register"; satu disebut "ruang pegang" yang tidak digunakan skrip Anda dan yang lainnya disebut "ruang pola". The Nperintah menambahkan baris baru dan dan baris berikutnya dari file input ke ruang pola. [* Anda dapat memiliki beberapa label & bperintah. Jika Anda memiliki bperintah tanpa label char ditambahkan padanya, itu bercabang di akhir skrip untuk membaca baris berikutnya dan mengulang lagi.]
Dijeda sampai pemberitahuan lebih lanjut.

108
Anda dapat menjalankan lintas-platform ini (yaitu pada Mac OS X) dengan secara terpisah mengeksekusi perintah daripada memisahkan dengan semi-titik dua: sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/ /g'
Benjie

74
Mengapa tidak ada yang mengomentari betapa bodohnya hal ini (bukan jawaban itu sendiri, tetapi program yang diajukan jawabannya adalah solusi terbaik untuk masalah yang sangat sederhana). Sed terlihat seperti mobil yang biasanya berjalan dengan baik, tetapi jika Anda ingin berkendara ke jalan tertentu di dekatnya, satu-satunya cara adalah mengangkat mobil dengan helikopter.
Ark-kun

12
Ayo orang-orang - 261 upvotes untuk solusi gila, tidak bisa dipahami yang tidak berhasil ???? sed adalah alat yang sangat baik untuk subtitle sederhana pada satu baris, untuk hal lain cukup gunakan awk. Astaga ....
Ed Morton

1711

seddimaksudkan untuk digunakan pada input berbasis garis. Meskipun dapat melakukan apa yang Anda butuhkan.


Opsi yang lebih baik di sini adalah menggunakan trperintah sebagai berikut:

tr '\n' ' ' < input_filename

atau hapus seluruhnya karakter baris baru:

tr -d '\n' < input.txt > output.txt

atau jika Anda memiliki versi GNU (dengan opsi yang panjang)

tr --delete '\n' < input.txt > output.txt

88
Sed adalah berbasis garis sehingga sulit baginya untuk memahami baris baru.
Alexander Gladysh

191
sed bekerja pada "aliran" input, tetapi memahaminya dalam potongan baris baru. Ini adalah alat unix, yang berarti melakukan satu hal dengan sangat baik. Satu hal adalah "bekerja berdasarkan file-bijaksana". Membuatnya melakukan sesuatu yang lain akan sulit, dan berisiko menjadi buggy. Moral dari cerita ini adalah: pilih alat yang tepat. Banyak sekali pertanyaan Anda yang berbentuk "Bagaimana saya bisa membuat alat ini melakukan sesuatu yang tidak pernah dimaksudkan untuk dilakukan?" Pertanyaan-pertanyaan itu menarik, tetapi jika muncul dalam penyelesaian masalah nyata, Anda mungkin salah melakukannya.
dmckee --- ex-moderator kitten

7
@JBBrown tradalah permata yang sering diabaikan untuk membangun jaringan pipa.
dmckee --- ex-moderator kitten

70
tr hebat, tetapi Anda hanya dapat mengganti baris baru dengan karakter tunggal. Anda perlu menggunakan alat lain jika Anda ingin mengganti baris baru dengan string
Eddy

21
@ Eddy - Saya menggunakan tr untuk mengganti baris baru dengan karakter yang tidak muncul dalam teks (saya menggunakan backtick), kemudian sed untuk mengganti backtick dengan string yang ingin saya gunakan
rjohnston

494

Jawaban cepat

sed ':a;N;$!ba;s/\n/ /g' file
  1. : a buat label 'a'
  2. N menambahkan baris berikutnya ke ruang pola
  3. $! jika bukan baris terakhir , ba cabang (buka) beri label 'a'
  4. s pengganti , / \ n / regex untuk baris baru , / / oleh ruang , / g pertandingan global (sebanyak yang bisa)

sed akan loop melalui langkah 1 hingga 3 hingga mencapai baris terakhir, mendapatkan semua baris pas di ruang pola di mana sed akan menggantikan semua \ n karakter


Alternatif

Semua alternatif, tidak seperti sed tidak perlu mencapai baris terakhir untuk memulai proses

dengan bash , lambat

while read line; do printf "%s" "$line "; done < file

dengan perl , kecepatan sed- like

perl -p -e 's/\n/ /' file

dengan tr , lebih cepat dari sed , dapat diganti dengan satu karakter saja

tr '\n' ' ' < file

dengan tempel , kecepatan mirip tr , dapat diganti dengan satu karakter saja

paste -s -d ' ' file

dengan awk , tr- like speed

awk 1 ORS=' ' file

Alternatif lain seperti "echo $ (<file)" lambat, hanya berfungsi pada file kecil dan perlu memproses seluruh file untuk memulai proses.


Jawaban panjang dari sed FAQ 5.10

5.10. Mengapa saya tidak dapat mencocokkan atau menghapus baris baru menggunakan
urutan melarikan diri \ n ? Mengapa saya tidak dapat mencocokkan 2 baris atau lebih menggunakan \ n?

\ N tidak akan pernah cocok dengan baris baru di akhir baris karena
baris baru selalu dibuka sebelum baris ditempatkan ke dalam
ruang pola. Untuk mendapatkan 2 garis atau lebih ke dalam ruang pola, gunakan
perintah 'N' atau yang serupa (seperti 'H; ...; g;').

Sed berfungsi seperti ini: sed membaca satu baris pada satu waktu, memotong
baris yang mengakhiri, menempatkan apa yang tersisa ke ruang pola di mana
skrip sed dapat mengatasi atau mengubahnya, dan ketika ruang pola
dicetak, menambahkan baris baru ke stdout (atau ke file). Jika
ruang pola dihapus seluruhnya atau sebagian dengan 'd' atau 'D',
baris baru tidak ditambahkan dalam kasus tersebut. Jadi, skrip suka

  sed 's/\n//' file       # to delete newlines from each line             
  sed 's/\n/foo\n/' file  # to add a word to the end of each line         

akan TIDAK PERNAH bekerja, karena baris baru trailing dihapus sebelum
garis dimasukkan ke dalam ruang pola. Untuk melakukan tugas di atas,
gunakan salah satu skrip ini sebagai gantinya:

  tr -d '\n' < file              # use tr to delete newlines              
  sed ':a;N;$!ba;s/\n//g' file   # GNU sed to delete newlines             
  sed 's/$/ foo/' file           # add "foo" to end of each line          

Karena versi sed selain GNU sed memiliki batasan ukuran
buffer pola, utilitas Unix 'tr' lebih disukai di sini.
Jika baris terakhir file berisi baris baru, GNU sed akan menambahkan
baris baru ke output tetapi
menghapus semua baris lainnya, sedangkan tr akan menghapus semua baris baru.

Untuk mencocokkan satu blok dengan dua baris atau lebih, ada 3 pilihan dasar:
(1) gunakan perintah 'N' untuk menambahkan baris Berikutnya ke ruang pola;
(2) gunakan perintah 'H' setidaknya dua kali untuk menambahkan garis saat ini
ke ruang Tahan, dan kemudian mengambil garis dari ruang tahan
dengan x, g, atau G; atau (3) menggunakan rentang alamat (lihat bagian 3.3, di atas)
untuk mencocokkan garis antara dua alamat yang ditentukan.

Pilihan (1) dan (2) akan menempatkan \ n ke dalam ruang pola, di mana ia
dapat dialamatkan sesuai keinginan ('s / ABC \ nXYZ / alfabet / g'). Salah satu contoh
menggunakan 'N' untuk menghapus blok garis muncul di bagian 4.13
("Bagaimana cara menghapus blok baris berturut - turut tertentu ?").
Contoh ini dapat dimodifikasi dengan mengubah perintah hapus ke sesuatu yang
lain, seperti 'p' (cetak), 'i' (masukkan), 'c' (ubah), 'a' (tambahkan),
atau 's' (pengganti) .

Choice (3) tidak akan menempatkan \ n ke dalam ruang pola, tetapi tidak
cocok dengan blok garis berturut-turut, sehingga mungkin bahwa Anda tidak
bahkan perlu \ n untuk menemukan apa yang Anda cari. Karena GNU sed
versi 3.02.80 sekarang mendukung sintaks ini:

  sed '/start/,+4d'  # to delete "start" plus the next 4 lines,           

selain alamat rentang tradisional '/ dari sini /, / ke sana / {...}
, dimungkinkan untuk menghindari penggunaan \ n seluruhnya.


6
tradalah ide yang bagus, dan cakupan keseluruhan Anda membuat jawaban berkualitas tinggi.
New Alexandria

1
+1 untuk menggunakan ( utilitas standar ) paste... dan yang lainnya!
Totor


4
Bagian terbaik tentang jawaban ini adalah bahwa "jawaban panjang" menjelaskan dengan tepat bagaimana dan mengapa perintah itu bekerja.
pdwalker

3
Ini mungkin yang paling membantu dari ribuan jawaban yang saya baca di stackexchange. Saya perlu mencocokkan banyak karakter di seluruh baris. Tidak ada contoh sed sebelumnya yang mencakup multi-baris dan tr tidak dapat menangani beberapa pencocokan karakter. Perl terlihat bagus, tetapi tidak berfungsi seperti yang saya harapkan. Saya akan memilih jawaban ini beberapa kali jika saya bisa.
mayypile

225

Alternatif awk yang lebih pendek:

awk 1 ORS=' '

Penjelasan

Program awk dibangun dari aturan yang terdiri dari kode-blok bersyarat, yaitu:

condition { code-block }

Jika kode-blok dihilangkan, default adalah digunakan: { print $0 }. Dengan demikian, 1ditafsirkan sebagai kondisi yang benar dan print $0dieksekusi untuk setiap baris.

Ketika awkmembaca input, ia membaginya menjadi catatan berdasarkan nilai RS(Pemisah Rekam), yang secara default adalah baris baru, sehingga awksecara default akan menguraikan jalur input secara bijak. Pemisahan juga melibatkan pengupasan RSdari catatan input.

Sekarang, saat mencetak catatan, ORS(Pemisah Catatan Keluaran) ditambahkan padanya, standarnya lagi adalah baris baru. Jadi dengan mengubah ORSke spasi semua baris baru diubah menjadi spasi.


5
Saya suka banyak solusi sederhana ini, yang jauh lebih mudah dibaca, daripada yang lain
Fedir RYKHTIK

8
Jika lebih masuk akal, ini dapat secara efektif ditulis sebagai: awk 'BEGIN { ORS=" " } { print $0 } END { print "\n"} ' file.txt(menambahkan baris akhir hanya untuk menggambarkan awal / akhir); "1" mengevaluasi untuk true(memproses garis) dan print(mencetak garis). Sebuah kondisional juga dapat ditambahkan ke ungkapan ini, misalnya, hanya bekerja pada garis yang cocok dengan pola: awk 'BEGIN { ORS=" " } /pattern/ { print $0 } END { print "\n"} '
michael

2
Anda dapat melakukannya lebih simle: codeawk 'ORS = ""' file.txtcode
Udi

Saat menggunakan awk seperti ini, sayangnya, umpan baris terakhir dalam file juga dihapus. Lihat Patrick Dark jawaban di atas tentang menggunakan 'tr' dalam subkulit seperti `file cat | echo $ (tr "\ 012" "") `yang berhasil. Bagus.
Bernie Reiter

143

gnu sed memiliki opsi -zuntuk catatan yang dipisahkan nol (baris). Anda cukup menelepon:

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

4
Bahkan jika inputnya mengandung null, mereka akan dipertahankan (sebagai pembatas rekaman).
Toby Speight

6
Bukankah ini akan memuat seluruh input jika tidak ada nulls? Dalam hal ini pemrosesan file multi-gigabyte mungkin macet.
Ruslan

3
@ Ruslan, ya itu memuat seluruh input. Solusi ini bukan ide yang baik untuk file multi-gigabyte.
JJoao

7
Ini benar-benar jawaban terbaik . Ekspresi lain terlalu berkerut untuk diingat. @ Jojo Anda dapat menggunakannya dengan -u, --unbuffered. Ituman negara Mage: "memuat jumlah minimal data dari file input dan menyiram output buffer lebih sering".
not2qubit

begitu. banyak. ini.
sjas

85

Versi Perl bekerja seperti yang Anda harapkan.

perl -i -p -e 's/\n//' file

Seperti yang ditunjukkan dalam komentar, perlu dicatat bahwa ini sudah diedit. -i.bakakan memberi Anda cadangan dari file asli sebelum penggantian jika ekspresi reguler Anda tidak sepandai yang Anda kira.


23
Harap setidaknya menyebutkan bahwa -itanpa akhiran tidak membuat cadangan . -i.bakmelindungi Anda dari kesalahan yang mudah dan jelek (misalnya, lupa mengetik -pdan memusatkan perhatian pada file).
Telemakus

6
@ Selemachus: Ini poin yang adil, tapi bisa dibantah. Alasan utama saya tidak menyebutkannya adalah bahwa contoh sed dalam pertanyaan OP tidak membuat cadangan, jadi sepertinya berlebihan di sini. Alasan lainnya adalah karena saya tidak pernah benar-benar menggunakan fungsionalitas cadangan (sebenarnya, saya menemukan cadangan otomatis mengganggu), jadi saya selalu lupa itu ada di sana. Alasan ketiga adalah itu membuat baris perintah saya empat karakter lebih lama. Untuk yang lebih baik atau lebih buruk (mungkin lebih buruk), saya seorang minimalis kompulsif; Saya hanya lebih suka singkatnya. Saya sadar Anda tidak setuju. Saya akan mencoba yang terbaik untuk mengingat untuk memperingatkan tentang cadangan di masa depan.
ire_and_curses

6
@Ire_and_curses: Sebenarnya, Anda baru saja membuat argumen yang bagus untuk mengabaikan saya. Artinya, Anda punya alasan untuk pilihan Anda, dan apakah saya setuju atau tidak dengan pilihan itu, saya tentu menghargai itu. Saya tidak yakin sepenuhnya mengapa, tapi saya sudah kehancuran tentang hal khusus ini akhir-akhir ini ( -ibendera di Perl tanpa akhiran). Saya yakin saya akan menemukan sesuatu yang lain untuk segera terobsesi. :)
Telemachus

Sangat disayangkan bahwa ini tidak bekerja dengan stdin dengan menentukan -nama file. Apakah ada cara untuk melakukan itu? Itu cara masuk saya untuk tidak khawatir tentang memodifikasi file menggunakan pipa yang dimulai dengan cat.
Steven Lu

@StevenLu Perl akan membaca dari STDIN secara default jika tidak ada nama file yang disediakan. Jadi Anda bisa melakukan misperl -i -p -e 's/\n//' < infile > outfile
ire_and_curses

44

Siapa yang butuh sed? Inilah bashcaranya:

cat test.txt |  while read line; do echo -n "$line "; done

2
Upvote, saya biasanya menggunakan jawaban teratas, tetapi ketika mem-pip / dev / urandom melaluinya, sed tidak akan mencetak sampai EOF, dan ^ C bukan EOF. Solusi ini mencetak setiap kali melihat baris baru. Apa yang saya butuhkan! Terima kasih!
Vasiliy Sharapov

1
lalu mengapa tidak: echo -n `cat days.txt` Dari pos ini
Tony

9
@Tony karena backticks sudah usang dan kucing itu berlebihan ;-) Gunakan: echo $ (<days.txt)
seumasmac

10
Tanpa menggunakan cat: while read line; do echo -n "$line "; done < test.txt. Mungkin bermanfaat jika sub-shell adalah masalah.
Carlo Cannas

5
echo $(<file)meremas semua spasi putih ke satu ruang, bukan hanya baris baru: ini melampaui apa yang diminta OP.
glenn jackman

27

Untuk mengganti semua baris baru dengan spasi menggunakan awk, tanpa membaca seluruh file ke dalam memori:

awk '{printf "%s ", $0}' inputfile

Jika Anda ingin baris baru final:

awk '{printf "%s ", $0} END {printf "\n"}' inputfile

Anda dapat menggunakan karakter selain spasi:

awk '{printf "%s|", $0} END {printf "\n"}' inputfile

END{ print ""}adalah alternatif yang lebih pendek untuk baris baru.
Isaac

22
tr '\n' ' ' 

adalah perintah.

Sederhana dan mudah digunakan.


14
atau hanya tr -d '\n'jika Anda tidak ingin menambahkan spasi
penggerutu

21

Tiga hal.

  1. tr(atau cat, dll.) sama sekali tidak diperlukan. (GNU) seddan (GNU) awk, bila digabungkan, dapat melakukan 99,9% dari semua pemrosesan teks yang Anda butuhkan.

  2. stream! = berbasis garis. edadalah editor berbasis baris. sedtidak. Lihat kuliah sed untuk informasi lebih lanjut tentang perbedaannya. Kebanyakan orang bingung sedmenjadi berbasis garis karena, secara default, tidak terlalu serakah dalam pencocokan pola untuk pencocokan SIMPLE - misalnya, ketika melakukan pencarian pola dan mengganti dengan satu atau dua karakter, secara default hanya menggantikan pada pencocokan pertama ia menemukan (kecuali ditentukan lain oleh perintah global). Bahkan tidak akan ada perintah global jika itu berbasis garis daripada berbasis STREAM, karena hanya akan mengevaluasi baris pada satu waktu. Coba jalankan ed; Anda akan melihat perbedaannya. edcukup berguna jika Anda ingin beralih pada baris tertentu (seperti dalam for-loop), tetapi sebagian besar waktu yang Anda inginkan sed.

  3. Yang telah dibilang,

    sed -e '{:q;N;s/\n/ /g;t q}' file
    

    berfungsi dengan baik di GNU sedversi 4.2.1. Perintah di atas akan mengganti semua baris baru dengan spasi. Ini jelek dan agak rumit untuk mengetik, tetapi berfungsi dengan baik. Itu {}bisa ditinggalkan, karena mereka hanya termasuk untuk alasan kewarasan.


3
Sebagai orang yang hanya cukup tahu seduntuk melakukan hal-hal dasar, saya harus mengatakan itu lebih dari tentang apa yang dapat Anda lakukan, sedtetapi betapa mudahnya untuk memahami apa yang sedang terjadi. Saya sangat kesulitan bekerja sedsehingga saya lebih suka perintah yang lebih sederhana ketika saya bisa menggunakannya.
Nate

Menggunakan t qlompatan bersyarat ini berfungsi dengan pola seperti s/\n / /(untuk bergabung dengan semua baris yang dimulai dengan spasi) tanpa membaca seluruh file ke dalam memori. Berguna saat mentransformasikan file multi megabyte.
textshell

Artikel yang Anda
tautkan

Ini hampir 800 kali lebih lambat daripada jawaban yang diterima pada input besar. Ini karena menjalankan pengganti untuk setiap baris pada input yang semakin besar.
Thor

13

Jawabannya dengan: label ...

Bagaimana saya bisa mengganti baris baru (\ n) menggunakan sed?

... tidak bekerja di freebsd 7.2 pada baris perintah:

(echo foo; echo bar) | sed ': a; N; $! ba; s / \ n / / g'
sed: 1: ": a; N; $! ba; s / \ n / / g": label yang tidak digunakan 'a; N; $! ba; s / \ n / / g'
foo
batang

Tetapi apakah jika Anda meletakkan skrip sed dalam file atau menggunakan -e untuk "membangun" skrip sed ...

> (echo foo; echo bar) | sed -e: a -e N -e '$! ba' -e 's / \ n / / g'
bar foo

atau ...

> cat > x.sed << eof
:a
N
$!ba
s/\n/ /g
eof

> (echo foo; echo bar) | sed -f x.sed
foo bar

Mungkin sed di OS X serupa.


Serangkaian argumen -e bekerja untuk saya di windows menggunakan MKS! Terima kasih!
JamesG

12

Solusi yang mudah dipahami

Saya punya masalah ini. Kicker adalah bahwa saya membutuhkan solusi untuk bekerja pada BSD (Mac OS X) dan GNU (Linux dan Cygwin ) seddan tr:

$ echo 'foo
bar
baz


foo2
bar2
baz2' \
| tr '\n' '\000' \
| sed 's:\x00\x00.*:\n:g' \
| tr '\000' '\n'

Keluaran:

foo
bar
baz

(telah mengikuti baris baru)

Ia bekerja di Linux, OS X, dan BSD - bahkan tanpa dukungan UTF-8 atau dengan terminal jelek.

  1. Gunakan truntuk menukar baris baru dengan karakter lain.

    NULL( \000atau \x00) bagus karena tidak memerlukan dukungan UTF-8 dan sepertinya tidak akan digunakan.

  2. Gunakan seduntuk mencocokkanNULL

  3. Gunakan truntuk menukar kembali baris baru tambahan jika Anda membutuhkannya


1
Catatan halus pada nomenklatur: karakter \000biasanya disebut sebagai NUL(satu L), dan NULLumumnya digunakan ketika berbicara tentang pointer nol (dalam C / C ++).
sqweek


9

Saya bukan ahli, tapi saya kira sedAnda pertama-tama harus menambahkan baris berikutnya ke dalam ruang pola, bij menggunakan " N". Dari bagian "Multiline Pattern Space" di "Advanced sed Commands" dari buku sed & awk (Dale Dougherty dan Arnold Robbins; O'Reilly 1997; halaman 107 dalam pratinjau ):

Perintah multiline Next (N) menciptakan ruang pola multiline dengan membaca baris input baru dan menambahkannya ke isi ruang pola. Isi asli dari ruang pola dan jalur input baru dipisahkan oleh baris baru. Karakter baris baru yang disematkan dapat dicocokkan dalam pola dengan urutan keluar "\ n". Dalam ruang pola multiline, metacharacter "^" cocok dengan karakter pertama dari ruang pola, dan bukan karakter yang mengikuti baris baru yang disematkan. Demikian pula, "$" hanya cocok dengan baris baru terakhir dalam ruang pola, dan bukan baris baru yang disematkan. Setelah perintah Berikutnya dijalankan, kontrol kemudian diteruskan ke perintah selanjutnya dalam skrip.

Dari man sed:

[2addr] N

Tambahkan baris input berikutnya ke ruang pola, menggunakan karakter baris baru yang disematkan untuk memisahkan bahan yang ditambahkan dari konten asli. Perhatikan bahwa nomor baris saat ini berubah.

Saya telah menggunakan ini untuk mencari (banyak) file log berformat buruk, di mana string pencarian dapat ditemukan pada baris berikutnya "yatim".


7

Saya menggunakan pendekatan hybrid untuk menyiasati hal baris baru dengan menggunakan tr untuk mengganti baris baru dengan tab, kemudian mengganti tab dengan apa pun yang saya inginkan. Dalam hal ini, "
" karena saya mencoba membuat HTML break.

echo -e "a\nb\nc\n" |tr '\n' '\t' | sed 's/\t/ <br> /g'`

6

Menanggapi solusi "tr" di atas, pada Windows (mungkin menggunakan versi Gnuwin32 tr), solusi yang diusulkan:

tr '\n' ' ' < input

tidak berfungsi untuk saya, entah karena kesalahan atau benar-benar mengganti \ nw / '' karena suatu alasan.

Menggunakan fitur lain dari tr, opsi "delete" -d berhasil meskipun:

tr -d '\n' < input

atau '\ r \ n' alih-alih '\ n'


3
Di Windows, Anda mungkin perlu menggunakan tr "\n" " " < input. Shell Windows (cmd.exe) tidak memperlakukan apostrof sebagai karakter kutip.
Keith Thompson

Tidak, di subsistem Windows 10 Ubuntu, Anda perlu menggunakantr "\n\r" " " < input.txt > output.txt
user1491819

Ini bekerja pada Windows 10 menggunakan GnuWin32: cat SourceFile.txt | tr --delete '\r\n' > OutputFile.txt. Atau, sebagai ganti Gnuwin32, gunakan Gow (Gnu di Windows), github.com/bmatzelle/gow/wiki
Alchemistmatt

5

Solusi anti peluru. Biner-data-aman dan POSIX-compliant, tetapi lambat.

POSIX sed memerlukan input sesuai dengan file teks POSIX dan baris POSIX definisi , sehingga NULL-byte dan garis yang terlalu panjang tidak diperbolehkan dan setiap baris harus diakhiri dengan baris baru (termasuk baris terakhir). Ini membuat sulit untuk menggunakan sed untuk memproses data input sewenang-wenang.

Solusi berikut ini menghindari sed dan alih-alih mengubah byte input ke kode oktal dan kemudian ke byte lagi, tetapi memotong kode oktal 012 (baris baru) dan mengeluarkan string pengganti sebagai pengganti. Sejauh yang saya tahu solusinya adalah POSIX-compliant, jadi itu harus bekerja pada berbagai platform.

od -A n -t o1 -v | tr ' \t' '\n\n' | grep . |
  while read x; do [ "0$x" -eq 012 ] && printf '<br>\n' || printf "\\$x"; done

Dokumentasi referensi POSIX: sh , bahasa perintah shell , od , tr , grep , baca , [ , printf .

Keduanya read,, [dan printfbuilt-in setidaknya dalam bash, tetapi itu mungkin tidak dijamin oleh POSIX, jadi pada beberapa platform bisa jadi setiap byte input akan memulai satu atau lebih proses baru, yang akan memperlambat segalanya. Bahkan dalam bash solusi ini hanya mencapai sekitar 50 kB / s, sehingga tidak cocok untuk file besar.

Diuji pada Ubuntu (bash, dash, dan busybox), FreeBSD, dan OpenBSD.


5

Dalam beberapa situasi mungkin Anda dapat mengubah RSstring atau karakter lain. Dengan cara ini, \ n tersedia untuk sub / gsub:

$ gawk 'BEGIN {RS="dn" } {gsub("\n"," ") ;print $0 }' file

Kekuatan skrip shell adalah bahwa jika Anda tidak tahu cara melakukannya dengan satu cara Anda dapat melakukannya dengan cara lain. Dan sering kali Anda memiliki lebih banyak hal untuk dipertimbangkan daripada membuat solusi yang kompleks pada masalah sederhana.

Mengenai hal yang gawk lambat ... dan membaca file ke dalam memori, saya tidak tahu ini, tetapi bagi saya gawk tampaknya bekerja dengan satu baris pada saat itu dan sangat sangat cepat (tidak secepat beberapa yang lain , tetapi waktu untuk menulis dan menguji juga diperhitungkan).

Saya memproses MB dan bahkan GB data, dan satu-satunya batas yang saya temukan adalah ukuran garis.


5

Jika Anda kurang beruntung harus berurusan dengan ujung baris windows Anda harus menghapus \rdan\n

tr '[\r\n]' ' ' < $input > $output

Ini menggantikan [dengan ruang, dan \rdengan ruang, dan \ndengan ruang, dan ]dengan ruang. tr -d '\r\n' <fileakan menghapus karakter \ratau apa pun \n, tetapi bukan itu yang ditanyakan. tr -d '\r' <fileakan menghapus semua \rkarakter (terlepas dari apakah mereka berdekatan \n) yang mungkin lebih dekat dengan berguna serta sangat mungkin benar untuk kebutuhan OP (masih dengan asumsi Anda trmemahami notasi backslash ini).
tripleee

4

Anda dapat menggunakan xargs- ini akan diganti \ndengan spasi secara default.

Namun, itu akan memiliki masalah jika input Anda memiliki kasus unterminated quote, misalnya, jika tanda kutip pada baris yang diberikan tidak cocok.


xargs juga menangani baris terakhir dengan baik:
AAAfarmclub

4

Temukan dan gantikan dengan menggunakan \ n

sed -ie -z 's/Marker\n/# Marker Comment\nMarker\n/g' myfile.txt

Penanda

Menjadi

# Komentar Penanda

Penanda


4

Mengapa saya tidak menemukan solusi sederhana dengan awk?

awk '{printf $0}' file

printf akan mencetak setiap baris tanpa baris baru, jika Anda ingin memisahkan garis asli dengan spasi atau lainnya:

awk '{printf $0 " "}' file

echo "1\n2\n3" | awk '{printf $0}', ini bekerja untuk saya. @ edi9999
Itachi

Maaf, saya lupa fprintf
edi9999

ini adalah satu-satunya pendekatan yang bekerja untuk saya dalam git bash for windows
Plato

3

Di Mac OS X (menggunakan FreeBSD sed):

# replace each newline with a space
printf "a\nb\nc\nd\ne\nf" | sed -E -e :a -e '$!N; s/\n/ /g; ta'
printf "a\nb\nc\nd\ne\nf" | sed -E -e :a -e '$!N; s/\n/ /g' -e ta


3

Menggunakan Awk:

awk "BEGIN { o=\"\" }  { o=o \" \" \$0 }  END { print o; }"

2
Anda tidak perlu keluar dari tanda kutip dan tanda dolar jika Anda mengubah yang luar menjadi tanda kutip tunggal. Huruf "o" biasanya dianggap sebagai pilihan yang salah sebagai nama variabel karena dapat dikacaukan dengan angka "0". Anda juga tidak perlu menginisialisasi variabel Anda, itu default ke string nol. Namun, jika Anda tidak ingin ruang terkemuka asing: awk '{s = s sp $0; sp = " "} END {print s}'. Namun, lihat jawaban saya untuk cara menggunakan awk tanpa membaca seluruh file ke dalam memori.
Dijeda sampai pemberitahuan lebih lanjut.

Silakan periksa jawaban Thor sebagai gantinya. Cara ini jauh lebih efisien, mudah dibaca, dan lebih baik dibandingkan dengan membandingkan semua pendekatan ini (meskipun ini akan berhasil)!
mschilli

Bung, saya mengerti. Tidak perlu mengoleskannya di wajah saya :-) Jawaban Thor jauh di atas pada halaman (yang benar), jadi apa peduli Anda?
kralyk

3

Solusi yang paling saya sukai adalah menambahkan semua file di ruang penyimpanan dan mengganti semua baris baru di akhir file:

$ (echo foo; echo bar) | sed -n 'H;${x;s/\n//g;p;}'
foobar

Namun, seseorang mengatakan kepada saya ruang penahanan dapat terbatas dalam beberapa implementasi sed.


1
penggantian dengan string kosong di jawaban Anda menyembunyikan fakta bahwa selalu menggunakan H untuk menambah ruang penahanan berarti ruang penahanan akan mulai dengan baris baru. Untuk menghindari ini, Anda perlu menggunakan1h;2,$H;${x;s/\n/x/g;p}
Jeff

3

Ganti baris baru dengan string apa pun, dan ganti baris baru terakhir juga

trSolusi murni hanya dapat menggantikan dengan karakter tunggal, dan sedsolusi murni tidak menggantikan baris baru terakhir input. Solusi berikut memperbaiki masalah ini, dan tampaknya aman untuk data biner (bahkan dengan lokal UTF-8):

printf '1\n2\n3\n' |
  sed 's/%/%p/g;s/@/%a/g' | tr '\n' @ | sed 's/@/<br>/g;s/%a/@/g;s/%p/%/g'

Hasil:

1<br>2<br>3<br>

Ini buruk karena akan menghasilkan output yang tidak diinginkan pada input yang mengandung@
Steven Lu

@ Svenvenu: Tidak, @dalam input OK. Ia lolos ke %adan kembali lagi. Solusinya mungkin tidak sepenuhnya sesuai dengan POSIX, (NULL-byte tidak diizinkan sehingga tidak baik untuk data biner, dan semua baris harus diakhiri dengan baris baru sehingga trhasilnya tidak benar-benar valid).
Håkon A. Hjortland

Ah. Saya melihat Anda sudah memperbaikinya. Agak berbelit-belit untuk apa yang harus operasi sederhana, tetapi kerja yang baik.
Steven Lu

3

Ini adalah sed yang memperkenalkan baris baru setelah substitusi "normal". Pertama, ia memangkas char baris baru, kemudian memproses sesuai dengan instruksi Anda, kemudian memperkenalkan baris baru.

Dengan menggunakan sed, Anda dapat mengganti "akhir" dari suatu baris (bukan karakter baris baru) setelah dipotong, dengan string pilihan Anda, untuk setiap baris input; tetapi, sed akan menampilkan garis yang berbeda. Misalnya, Anda ingin mengganti "ujung garis" dengan "===" (lebih umum daripada mengganti dengan spasi tunggal):

PROMPT~$ cat <<EOF |sed 's/$/===/g'
first line
second line
3rd line
EOF

first line===
second line===
3rd line===
PROMPT~$

Untuk mengganti karakter baris baru dengan string, Anda dapat, secara tidak efisien, menggunakan tr , seperti yang ditunjukkan sebelumnya, untuk mengganti karakter baris baru dengan "karakter khusus" dan kemudian menggunakan sed untuk mengganti karakter khusus dengan string yang Anda inginkan. .

Sebagai contoh:

PROMPT~$ cat <<EOF | tr '\n' $'\x01'|sed -e 's/\x01/===/g'
first line
second line
3rd line
EOF

first line===second line===3rd line===PROMPT~$

3

Anda dapat menggunakan metode ini juga

sed 'x;G;1!h;s/\n/ /g;$!d'

Penjelasan

x   - which is used to exchange the data from both space (pattern and hold).
G   - which is used to append the data from hold space to pattern space.
h   - which is used to copy the pattern space to hold space.
1!h - During first line won't copy pattern space to hold space due to \n is
      available in pattern space.
$!d - Clear the pattern space every time before getting next line until the
      last line.

Aliran:
Ketika baris pertama dapatkan dari input, pertukaran dilakukan, jadi 1 pergi ke ruang penyimpanan dan \ n datang ke ruang pola, kemudian menambahkan ruang tahan ke ruang pola, dan kemudian substitusi dilakukan dan menghapus ruang pola.
Selama pertukaran baris kedua dilakukan, 2 pergi ke ruang penahanan dan 1 datang ke ruang pola, kemudian Gmenambahkan ruang penahanan ke dalam ruang pola, lalu hmenyalin pola itu dan substitusi dibuat dan dihapus. Operasi ini dilanjutkan sampai tercapai, kemudian cetak hasil yang tepat.


Namun, berhati-hatilah karena echo 'Y' | sed 'x;G;1!h;s/\n/X/g;$!d'hasilnya XY.
Spooky

3

Lain GNU sed metode, hampir sama dengan Zsolt Botykai 'jawaban s , tapi ini menggunakan sed' s kurang sering digunakan y( transliterasi ) perintah, yang menyimpan satu byte kode (trailing g):

sed ':a;N;$!ba;y/\n/ /'

Orang akan berharap yakan berjalan lebih cepat daripada s, (mungkin pada trkecepatan, 20x lebih cepat), tetapi dalam GNU sed v4.2.2 y adalah sekitar 4% lebih lambat daripada s.


Versi BSD yang lebih portabel sed:

sed -e ':a' -e 'N;$!ba' -e 'y/\n/ /'

2
Dengan BSD sed yadalah ca 15% lebih cepat. Lihat jawaban ini untuk contoh yang berfungsi.
Thor

Juga, dengan BSD perintah sed harus diakhiri setelah label, jadi sed -e ':a' -e 'N;$!ba' -e 'y/\n/ /'akan menjadi cara untuk pergi.
ghoti
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.