Bagaimana cara mengganti string yang mengandung garis miring dengan sed?

147

Saya memiliki proyek Visual Studio, yang dikembangkan secara lokal. File kode harus dikerahkan ke server jauh. Satu-satunya masalah adalah URL yang mengandung kode-keras.

Proyek berisi URL seperti ? Halaman = satu . Agar tautan valid di server, tautannya harus / halaman / satu .

Saya telah memutuskan untuk mengganti semua URL di file code saya dengan sed sebelum penerapan, tapi saya terjebak pada garis miring.

Saya tahu ini bukan solusi yang bagus, tetapi sederhana akan menghemat banyak waktu. Total jumlah string yang harus saya ganti kurang dari 10. Jumlah total file yang harus diperiksa adalah ~ 30.

Contoh menggambarkan situasi saya di bawah ini:

Perintah saya menggunakan:

sed -f replace.txt < a.txt > b.txt

replace.txt yang berisi semua string:

s/?page=one&/pageone/g
s/?page=two&/pagetwo/g
s/?page=three&/pagethree/g

a.txt:

?page=one&
?page=two&
?page=three&

Konten b.txt setelah saya menjalankan perintah sed:

pageone
pagetwo
pagethree

Apa yang saya ingin b.txt mengandung:

/page/one
/page/two
/page/three
afaf12
sumber
1
mungkin duplikat dari pencarian sed dan ganti string yang mengandung /
Damien MATHIEU
3
kemungkinan duplikat dari garis miring Gunakan sebagai ganti
tripleee

Jawaban:

274

Cara termudah adalah dengan menggunakan pembatas yang berbeda dalam pencarian Anda / ganti baris, misalnya:

s:?page=one&:pageone:g

Anda dapat menggunakan karakter apa pun sebagai pembatas yang bukan bagian dari string mana pun. Atau, Anda bisa menghindarinya dengan backslash:

s/\//foo/

Yang akan diganti /dengan foo. Anda ingin menggunakan backslash yang lolos dalam kasus di mana Anda tidak tahu karakter apa yang mungkin terjadi dalam string pengganti (misalnya, mereka adalah variabel shell, misalnya).

lurker
sumber
1
> Atau, Anda bisa menghindarinya dengan backslash. Contohnya akan lebih bermanfaat, karena Anda tidak selalu tahu karakter apa yang ada di string untuk dapat memilih sesuatu yang berbeda. misalnya, ini: echo / | sed s / \ // a / g tidak berfungsi: sed: -e ekspresi # 1, char 5: opsi tidak diketahui untuk `s '
Max Waterman
1
Bisakah Anda menambahkannya? Terima kasih :) Saya menemukan sekelilingnya dalam tanda kutip ganda sepertinya berfungsi: echo / | sed "s / \ // a / g"
Max Waterman
@ MaxWaterman itu prosedur operasi standar ketika menggunakan sedperintah regex dimasukkan dalam tanda kutip ganda. Saya tidak menggunakannya dalam jawaban saya karena saya tidak menunjukkan seluruh sedbaris perintah tetapi hanya sedstring perintah regex seperti yang telah dilakukan OP. Jika Anda memasukkannya ke dalam file, seperti OP, Anda tidak perlu tanda kutip.
lurker
Ya, cukup adil (meskipun mungkin bisa disebutkan). Contoh itu membantu. Saya telah menemukan saya perlu memasukkan banyak backslash kadang-kadang ... dan itu menjadi sangat membingungkan. misalnya -e "s / '/ \\\ & & g" Saya pikir teksnya salah, meskipun: "Yang akan menggantikan \ dengan foo" - harus "Yang akan mengganti / dengan foo", bukan?
Max Waterman
@ MaxWaterman terima kasih telah menangkapnya di \ vs. /. Memperbaikinya. Jika Anda memiliki sedperintah dalam skrip shell, maka mungkin backslash lebih banyak (setiap backslash perlu di-backslash lagi).
lurker
105

The sperintah dapat menggunakan karakter apapun sebagai pembatas; karakter apa pun yang muncul setelah sdigunakan. Saya dibesarkan untuk menggunakan a #. Seperti itu:

s#?page=one&#/page/one#g
Tom Anderson
sumber
5
Halaman manual untuk sed BSD pada OS X mengatakan tentang perintah s : Ganti string pengganti untuk instance pertama dari ekspresi reguler dalam ruang pola. Karakter apa pun selain garis miring terbalik atau baris baru dapat digunakan sebagai ganti garis miring untuk membatasi RE dan penggantian. Saya berani bertaruh uang bahwa halaman manual untuk GNU sed mengatakan sesuatu yang serupa.
Tom Anderson
Jawaban yang diterima saat ini pada dasarnya sama dengan yang ini, dan telah diposting satu menit sebelumnya!
Tom Anderson
61

Fakta yang sangat berguna tetapi kurang diketahui tentang sed adalah bahwa s/foo/bar/perintah yang akrab dapat menggunakan tanda baca apa pun, tidak hanya garis miring. Alternatif umum adalah s@foo@bar@, dari situ menjadi jelas bagaimana menyelesaikan masalah Anda.

John Zwinck
sumber
Saran jenius saat Anda ingin mengganti garis miring ke depan. Terima kasih!
mbb
9

tambahkan \ sebelum karakter khusus:

s/\?page=one&/page\/one\//g

dll.

Ilja
sumber
4
Saya mungkin telah melewatkan sesuatu, tetapi saya sudah mencoba ini dan sepertinya tidak berhasil. Tampaknya memang hal yang jelas untuk dicoba, tetapi dengan asumsi saya benar dan memang tidak berhasil, mengapa mempostingnya?
codenoob
4
@codenoob (dan siapa pun yang tiba di sini) - 's' pada awalnya diperlukan. s/foo\/bar/foo_bar/akan bekerja, tetapi /foo\/bar/foo_bar/tidak akan.
MynockSpit
5

Dalam sistem yang saya kembangkan, string yang akan diganti oleh sed adalah input teks dari pengguna yang disimpan dalam variabel dan diteruskan ke sed.

Seperti disebutkan sebelumnya pada posting ini, jika string yang terkandung dalam blok perintah sed berisi pembatas aktual yang digunakan oleh sed - maka sed berakhir pada kesalahan sintaks. Perhatikan contoh berikut:

Ini bekerja:

$ VALUE=12345
$ echo "MyVar=%DEF_VALUE%" | sed -e s/%DEF_VALUE%/${VALUE}/g
MyVar=12345

Ini istirahat:

$ VALUE=12345/6
$ echo "MyVar=%DEF_VALUE%" | sed -e s/%DEF_VALUE%/${VALUE}/g
sed: -e expression #1, char 21: unknown option to `s'

Mengganti pembatas default bukanlah solusi yang kuat dalam kasus saya karena saya tidak ingin membatasi pengguna untuk memasukkan karakter tertentu yang digunakan oleh sed sebagai pembatas (misalnya "/").

Namun, menghindari kemunculan pembatas dalam string input akan menyelesaikan masalah. Pertimbangkan solusi di bawah ini untuk secara sistematis keluar dari karakter pembatas di string input sebelum diuraikan oleh sed. Melarikan diri seperti itu dapat diimplementasikan sebagai pengganti menggunakan sed itu sendiri, penggantian ini aman bahkan jika string input berisi pembatas - ini karena string input bukan bagian dari blok perintah sed:

$ VALUE=$(echo ${VALUE} | sed -e "s#/#\\\/#g")
$ echo "MyVar=%DEF_VALUE%" | sed -e s/%DEF_VALUE%/${VALUE}/g
MyVar=12345/6

Saya telah mengonversikan ini ke fungsi yang akan digunakan oleh berbagai skrip:

escapeForwardSlashes() {

     # Validate parameters
     if [ -z "$1" ]
     then
             echo -e "Error - no parameter specified!"
             return 1
     fi

     # Perform replacement
     echo ${1} | sed -e "s#/#\\\/#g"
     return 0
}
Yoav Drori
sumber
1
Yang perlu diambil dari jawaban Anda untuk saya, adalah bahwa jika VALUE yang Anda gunakan untuk menggantikan DEF_VALUE, memiliki garis miring di dalamnya, maka Anda harus menghindarinya dengan 3 garis miring terbalik agar dapat bekerja misalnyaVALUE="01\\\/01\\\/2018"
alexkb
3

baris ini akan bekerja untuk 3 contoh Anda:

sed -r 's#\?(page)=([^&]*)&#/\1/\2#g' a.txt
  • Saya digunakan -runtuk menyelamatkan beberapa melarikan diri.
  • baris harus generik untuk kasus Anda yang satu, dua, tiga. Anda tidak perlu melakukan sub 3 kali

uji dengan contoh Anda (a.txt):

kent$  echo "?page=one&
?page=two&
?page=three&"|sed -r 's#\?(page)=([^&]*)&#/\1/\2#g'
/page/one
/page/two
/page/three
Kent
sumber
1

replace.txt seharusnya

s/?page=/\/page\//g
s/&//g
Ion Cojocaru
sumber
1

Jawaban bagus dari Anonim. \ Memecahkan masalah saya ketika saya mencoba melarikan diri dari kutipan dalam string HTML.

Jadi, jika Anda menggunakan sed untuk mengembalikan beberapa templat HTML (di server), gunakan double backslash alih-alih tunggal:

var htmlTemplate = "<div style=\\"color:green;\\"></div>";
Sirar Salih
sumber
1

sedadalah s tream ed itor , karena Anda dapat menggunakan |(pipa) untuk mengirim standar stream (STDIN dan STDOUT khusus) melalui seddan mengubah mereka pemrograman dengan cepat, membuatnya menjadi alat yang berguna dalam tradisi filsafat Unix; tetapi dapat mengedit file secara langsung juga, menggunakan -iparameter yang disebutkan di bawah ini.
Pertimbangkan yang berikut ini :

sed -i -e 's/few/asd/g' hello.txt

s/digunakan untuk s ubstitute ekspresi ditemukan fewdengan asd:

Beberapa, berani.


ASD, pemberani.

/gsingkatan "global", artinya melakukan ini untuk seluruh lini. Jika Anda meninggalkan /g(dengan s/few/asd/, selalu harus ada tiga garis miring tidak peduli apa) dan fewmuncul dua kali pada baris yang sama, hanya yang pertama fewdiubah menjadi asd:

Beberapa pria, beberapa wanita, pemberani.


Laki-laki asd, beberapa perempuan, pemberani.

Ini berguna dalam beberapa keadaan, seperti mengubah karakter khusus di awal baris (misalnya, mengganti simbol lebih besar dari yang digunakan beberapa orang untuk mengutip materi sebelumnya di utas email dengan tab horizontal sambil meninggalkan ketidaksamaan aljabar yang dikutip kemudian di baris tersebut). tidak tersentuh), tetapi dalam contoh Anda di mana Anda menentukan bahwa di mana saja few terjadi itu harus diganti, pastikan Anda memilikinya /g.

Dua opsi berikut (bendera) digabungkan menjadi satu -ie,:

-iPilihan ini digunakan untuk mengedit i n tempat pada file tersebut hello.txt.

-eOpsi menunjukkan e xpression / perintah untuk dijalankan, dalam hal ini s/.

Catatan: Penting untuk Anda gunakan -i -euntuk mencari / mengganti. Jika Anda melakukannya -ie, Anda membuat cadangan setiap file dengan huruf 'e' ditambahkan.

Chaminda Bandara
sumber
0

Alternatif sederhana menggunakan AWK seperti pada jawaban ini :

awk '$0="prefix"$0' file > new_file

Menandai
sumber