Bagaimana cara menyisipkan baris baru di depan pola?


139

Bagaimana cara menyisipkan baris baru sebelum pola dalam satu baris?

Misalnya, ini akan menyisipkan baris baru di belakang pola regex.

sed 's/regex/&\n/g'

Bagaimana saya bisa melakukan hal yang sama tetapi di depan polanya?

Dengan contoh file masukan ini, pola yang akan dicocokkan adalah nomor telepon.

some text (012)345-6789

Harus menjadi

some text
(012)345-6789


1
@NilsvonBarth, mengapa pertanyaan langsung adalah pertanyaan yang buruk?
Josh

Jawaban:


181

Ini berfungsi di bashdan zsh, diuji di Linux dan OS X:

sed 's/regexp/\'$'\n/g'

Secara umum, for $diikuti oleh string literal dalam tanda kutip tunggal bashmelakukan substitusi backslash gaya C, misalnya $'\t'diterjemahkan ke tab literal. Plus, sed ingin literal baris baru Anda di-escape dengan garis miring terbalik, maka \sebelumnya $. Dan akhirnya, tanda dolar itu sendiri tidak boleh dikutip sehingga ditafsirkan oleh shell, oleh karena itu kita menutup kutipan sebelum $dan kemudian membukanya lagi.

Sunting : Seperti yang disarankan dalam komentar oleh @ mklement0, ini juga berfungsi:

sed $'s/regexp/\\\n/g'

Apa yang terjadi di sini adalah: seluruh perintah sed sekarang menjadi string gaya-C, yang berarti garis miring terbalik yang dibutuhkan sed untuk ditempatkan sebelum literal baris baru sekarang harus di-escape dengan garis miring terbalik lain. Meskipun lebih mudah dibaca, dalam hal ini Anda tidak akan dapat melakukan substitusi string shell (tanpa membuatnya jelek lagi.)


7
Ini memberi saya "baris baru yang tidak lolos di dalam pola pengganti" di OSX.
Matt Gibson

@Matt Gibson itu sangat aneh karena "baris baru yang tidak lolos" diberikan hanya jika Anda memiliki baris baru yang nyata tanpa garis miring terbalik dalam pola substitusi. Kode saya di atas berfungsi, sebenarnya, di beberapa shell lain juga, misalnya zsh, ksh.
mojuba

3
@Matt Gibson ... atau jika Anda lupa garis miring terbalik sebelum '$' \ n di kode saya.
mojuba

7
Seperti yang tertulis, ekspresi ini mengganti regex sepenuhnya dengan baris baru, bukan menyisipkan baris baru di tengah baris yang ada seperti yang diminta. Berikut adalah cara saya menggunakan bentuk modifikasi dari jawaban ini untuk menyisipkan baris baru antara dua pola cocok: sed '\(first match\)\(second match\)/\1\'$'\n''\2/g'. Perhatikan dua tanda kutip tunggal setelah \ n. Yang pertama menutup bagian " $" sehingga sisa baris tidak terpengaruh olehnya. Tanpa tanda kutip tersebut, \ 2 diabaikan.
David Ravetti

12
Pilihan lain adalah dengan menggunakan satu ANSI C-string dikutip : sed $'s/regexp/\\\n/g', yang meningkatkan keterbacaan - satu-satunya pengecualian adalah bahwa Anda kemudian harus menggandakan semua literal \ karakter.
mklement0

46

Beberapa jawaban lain tidak berfungsi untuk versi sed. Mengganti posisi &dan \nberhasil.

sed 's/regexp/\n&/g' 

Sunting: Ini sepertinya tidak berfungsi di OS X, kecuali Anda menginstal gnu-sed.


10
Saya tidak yakin ini berfungsi di semua versi sed. Saya mencoba ini di Mac saya dan \ n hanya mendapatkan keluaran sebagai 'n'
Todd Gamblin

4
Menghabiskan 15 menit di Mac di tempat kerja saya, sebelum membaca jawaban Anda. Ayo Apple!
Rick77

2
Bagi mereka yang menggunakan homebrew: brew install gnu-seddiikuti olehgsed 's/regexp/\n&/g'
aaaaaa

2
... diikuti olehecho 'alias sed=gsed' >> ~/.bashrc
Proximo

36

Sed, Anda tidak dapat menambahkan baris baru dalam arus keluaran dengan mudah. Anda perlu menggunakan garis lanjutan, yang canggung, tetapi berhasil:

$ sed 's/regexp/\
&/'

Contoh:

$ echo foo | sed 's/.*/\
&/'

foo

Lihat di sini untuk detailnya. Jika Anda menginginkan sesuatu yang tidak terlalu canggung, Anda dapat mencoba menggunakan perl -pedengan grup pencocokan alih-alih sed:

$ echo foo | perl -pe 's/(.*)/\n$1/'

foo

$1 merujuk ke grup pertama yang cocok dalam ekspresi reguler, dengan grup di dalam tanda kurung.


Mengapa Anda mengatakan Anda tidak dapat menambahkan baris baru? Anda cukup melakukan sed 's / regexp / & \ n / g' Itu saja
Andres

2
Ini adalah hal paling tidak menarik yang dapat Anda lakukan di Mac untuk memasukkan baris baru (\ n tidak berfungsi di mac)
Pylinux

Versi perl dapat dimodifikasi untuk melakukan pengeditan di tempatperl -pi -e 's/(.*)/\n$1/' foo
Eponymous

2
@Andres: (Kebanyakan) Implementasi Sed hanya-fitur-POSIX seperti versi BSD yang juga disertakan dengan OS X tidak mendukung urutan pelolosan karakter kontrol di bagian substitusi spemanggilan fungsi (tidak seperti implementasi GNU Sed, yang mendukung ) . Jawaban di atas berfungsi dengan kedua implementasi; untuk gambaran umum tentang semua perbedaan, lihat di sini .
mklement0

29

Di mac saya, berikut ini menyisipkan satu 'n' alih-alih baris baru:

sed 's/regexp/\n&/g'

Ini menggantikan dengan baris baru:

sed "s/regexp/\\`echo -e '\n\r'`/g"

Saya sedang melakukan pengeditan inline sed -i '' -e ...dan mengalami masalah dengan ^Mtanda sisipan M (ctrl + m) yang ditulis ke file. Saya akhirnya menggunakan perl dengan parameter yang sama.
Steve Tauber

2
Perlu diketahui fakta bahwa kode kedua menyisipkan kode baris baru khusus LF CR (kebalikan dari MS-DOS CR LF)! Baik OS mirip Unix dan Mac OS X hanya menggunakan LF ( \n).
pabouk

Sesuatu yang lain dalam ekspresi sed saya menyebabkan begitu banyak ketidakbahagiaan (meskipun itu berfungsi dengan baik tanpa echo...dan baris baru) sehingga saya hanya melakukan ini di vim.
Ahmed Fasih

1
Atau sederhananya: sed "s/regexp/`echo`/g"- ini akan menghasilkan satu LF, bukan LF-CR
mojuba

2
@mojuba: Tidak: `echo`akan menghasilkan string kosong , karena penggantian perintah selalu memotong semua baris baru yang tertinggal. Tidak ada cara untuk menggunakan substitusi perintah untuk langsung memasukkan satu baris baru (dan menyisipkan \n\r- misalnya, CR tambahan - adalah ide yang buruk).
mklement0

15
echo one,two,three | sed 's/,/\
/g'

1
+1 bekerja dengan sempurna dan cukup jujur ​​/ mudah diingat
gMale

2
Jawaban ini sebenarnya adalah solusi sed dan bukan solusi bash . Apa pun yang menggunakan konstruksi seperti $'\n'mengandalkan shell untuk menghasilkan baris baru. Solusi tersebut mungkin tidak portabel. Yang ini. Tentu saja, ini juga duplikat dari contoh kedua dalam jawaban tgamblin dari tahun 2009.
ghoti

10

Dalam hal ini, saya tidak menggunakan sed. Saya menggunakan tr.

cat Somefile |tr ',' '\012' 

Ini mengambil koma dan menggantinya dengan kembali kereta.


1
Saya menemukan ini juga berfungsi: cat Somefile | tr ',' '\n'YMMV
Mr. Lance E Sloan

10

Anda dapat menggunakan perl satu baris seperti yang Anda lakukan dengan sed, dengan keuntungan ekspresi reguler perl penuh dukungan (yang jauh lebih kuat daripada yang Anda dapatkan dengan sed). Ada juga variasi yang sangat sedikit di seluruh platform * nix - perl umumnya adalah perl. Jadi Anda bisa berhenti mencemaskan tentang bagaimana membuat versi sistem Anda sed melakukan apa yang Anda inginkan.

Dalam hal ini, Anda bisa melakukannya

perl -pe 's/(regex)/\n$1/'

-pe menempatkan perl ke dalam loop "eksekusi dan cetak", seperti mode operasi normal sed.

' mengutip yang lainnya sehingga shell tidak akan mengganggu

() mengelilingi regex adalah operator pengelompokan. $1di sisi kanan substitusi mencetak apa pun yang cocok di dalam tanda kurung ini.

Akhirnya, \nadalah baris baru.

Terlepas dari apakah Anda menggunakan tanda kurung sebagai operator pengelompokan, Anda harus keluar dari tanda kurung yang ingin Anda cocokkan. Jadi ekspresi reguler untuk mencocokkan pola yang Anda cantumkan di atas akan menjadi seperti ini

\(\d\d\d\)\d\d\d-\d\d\d\d

\(atau \)cocok dengan tanda kurung literal, dan \dcocok dengan digit.

Lebih baik:

\(\d{3}\)\d{3}-\d{4}

Saya membayangkan Anda bisa mengetahui apa yang dilakukan angka-angka di kawat gigi.

Selain itu, Anda dapat menggunakan pembatas selain / untuk ekspresi reguler Anda. Jadi jika Anda perlu mencocokkan / Anda tidak perlu menghindarinya. Salah satu dari berikut ini setara dengan ekspresi reguler di awal jawaban saya. Secara teori, Anda dapat mengganti karakter apa pun untuk standar /.

perl -pe 's#(regex)#\n$1#'
perl -pe 's{(regex)}{\n$1}'

Beberapa pemikiran terakhir.

menggunakan -nealih-alih melakukan -petindakan serupa, tetapi tidak secara otomatis mencetak di akhir. Ini bisa berguna jika Anda ingin mencetak sendiri. Misalnya, ini grep-alike ( m/foobar/adalah pertandingan regex):

perl -ne 'if (m/foobar/) {print}'

Jika Anda merasa berurusan dengan baris baru merepotkan, dan Anda ingin menangani hal itu secara ajaib, tambahkan -l. Tidak berguna untuk OP, yang bekerja dengan baris baru.

Tip bonus - jika Anda memiliki paket pcre yang terinstal, itu disertakan pcregrep, yang menggunakan regex lengkap yang kompatibel dengan perl.


4

Hmm, baris baru yang lolos begitu saja tampaknya berfungsi di versi yang lebih baru sed(Saya memiliki GNU sed 4.2.1),

dev:~/pg/services/places> echo 'foobar' | sed -r 's/(bar)/\n\1/;'
foo
bar

1
Seperti disebutkan, ini berfungsi dengan berbagai versi GNU sed, tetapi tidak sed yang disertakan dengan macOS.
Tn. Lance E Sloan

4
echo pattern | sed -E -e $'s/^(pattern)/\\\n\\1/'

bekerja dengan baik di El Captitan dengan ()dukungan


Ini bekerja dengan baik dan Anda bahkan memberikan perintah lengkap untuk menguji dan memperkirakan dari menjadi spesialis untuk tujuan Anda sendiri. Pekerjaan yang baik!
jxramos

3

Untuk memasukkan baris baru ke aliran keluaran di Linux, saya menggunakan:

sed -i "s/def/abc\\\ndef/" file1

Dimana file1:

def

Sebelum penggantian sed di tempat, dan:

abc
def

Setelah sed di tempat penggantian. Harap perhatikan penggunaan \\\n. Jika polanya memiliki bagian "dalam, hindari menggunakan \".


Bagi saya kode diatas tidak berfungsi. sedmenyisipkan \nalih-alih LF karena mendapat \\nparameter dari shell. --- Kode ini bekerja: sed -i "s/def/abc\ndef/" file1. --- GNU sed version 4.2.1, GNU bash, version 4.1.2(1) / 4.2.25(1)(CentOS rilis 6.4 / Ubuntu 12.04.3).
pabouk

2

sed Anda dapat mereferensikan grup dalam pola Anda dengan "\ 1", "\ 2", .... jadi jika pola yang Anda cari adalah "POLA", dan Anda ingin memasukkan "SEBELUMNYA" di depannya , Anda dapat menggunakan, tanpa melarikan diri

sed 's/(PATTERN)/BEFORE\1/g'

yaitu

  sed 's/\(PATTERN\)/BEFORE\1/g'

Baru saja: isi testfile = "ABC ABC ABC". Jalankan "sed 's / \ (ABC \) / \ n \ 1 / g' testfile, dapatkan baris baru. Eksperimen dengan escapes, coba tambahkan 1 hal pada satu waktu ke pola Anda, misalnya pastikan Anda mencocokkan pola, kemudian periksa kecocokan grup, lalu tambahkan pemeriksaan baris baru.
Steve B.

Saya baru saja mencoba persis seperti itu dan mendapatkan "nABC nABC nABC '. Apakah Anda menggunakan sed versi lain?
Todd Gamblin

pelarian shell mungkin menghalangi upaya tgamblin. menempatkan argumen sed lengkap dalam tanda kutip tunggal seperti yang dilakukan Steve B akan memperbaikinya. Meskipun demikian, versi sed yang berbeda mungkin tidak memahami \ n untuk baris baru.
Dan Pritts

2

Anda juga dapat melakukan ini dengan awk, menggunakan -vuntuk memberikan pola:

awk -v patt="pattern" '$0 ~ patt {gsub(patt, "\n"patt)}1' file

Ini memeriksa apakah garis berisi pola tertentu. Jika demikian, itu menambahkan baris baru ke awalnya.

Lihat contoh dasar:

$ cat file
hello
this is some pattern and we are going ahead
bye!
$ awk -v patt="pattern" '$0 ~ patt {gsub(patt, "\n"patt)}1' file
hello
this is some 
pattern and we are going ahead
bye!

Perhatikan itu akan mempengaruhi semua pola dalam satu baris:

$ cat file
this pattern is some pattern and we are going ahead
$ awk -v patt="pattern" '$0 ~ patt {gsub(patt, "\n"patt)}1' d
this 
pattern is some 
pattern and we are going ahead

1
apa yang 1 lakukan dalam hal ini?
whatahitson

1
@whatahitson 1digunakan di Awk sebagai singkatan dari {print $0}. Alasannya adalah bahwa kondisi apa pun yang mengevaluasi ke True memicu tindakan default AWK, yang terdiri dari pencetakan rekaman saat ini.
fedorqui 'SO berhenti melukai'

1

Ini bekerja di MAC untuk saya

sed -i.bak -e 's/regex/xregex/g' input.txt sed -i.bak -e 's/qregex/\'$'\nregex/g' input.txt

Dono apakah itu sempurna ...


1

Setelah membaca semua jawaban atas pertanyaan ini, saya masih perlu banyak upaya untuk mendapatkan sintaks yang benar ke skrip contoh berikut:

#!/bin/bash
# script: add_domain
# using fixed values instead of command line parameters $1, $2
# to show typical variable values in this example
ipaddr="127.0.0.1"
domain="example.com"
# no need to escape $ipaddr and $domain values if we use separate quotes.
sudo sed -i '$a \\n'"$ipaddr www.$domain $domain" /etc/hosts

Skrip menambahkan baris baru \ndiikuti dengan baris teks lain ke akhir file menggunakan satu sedperintah.


1
sed -e 's/regexp/\0\n/g'

\ 0 adalah nol, jadi ekspresi Anda diganti dengan nol (tidak ada) dan kemudian ...
\ n adalah baris baru

Pada beberapa rasa Unix tidak berfungsi, tetapi saya pikir itu adalah solusi untuk masalah Anda.

echo "Hello" | sed -e 's/Hello/\0\ntmow/g'
Hello
tmow

0

Di vi di Red Hat, saya bisa memasukkan carriage return hanya dengan menggunakan karakter \ r. Saya percaya ini secara internal mengeksekusi 'ex' daripada 'sed', tetapi serupa, dan vi bisa menjadi cara lain untuk melakukan pengeditan massal seperti tambalan kode. Sebagai contoh. Saya mengelilingi istilah pencarian dengan pernyataan if yang bersikeras bahwa kereta kembali setelah kurung kurawal:

:.,$s/\(my_function(.*)\)/if(!skip_option){\r\t\1\r\t}/

Perhatikan bahwa saya juga menyuruhnya memasukkan beberapa tab untuk membuat semuanya selaras lebih baik.


0

Dalam kasus saya, metode di bawah ini berfungsi.

sed -i 's/playstation/PS4/' input.txt

Dapat ditulis sebagai:

sed -i 's/playstation/PS4\nplaystation/' input.txt


Playstation PS4

Pertimbangkan untuk menggunakan \\ n saat menggunakannya dalam string literal.

  • sed : adalah editor aliran

  • -i : Memungkinkan untuk mengedit file sumber

  • + : Apakah pembatas.

Saya harap informasi di atas berfungsi untuk Anda πŸ˜ƒ.

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.