Saya ingin mengganti hanya k
contoh kata pertama.
Bagaimana saya bisa melakukan ini?
Misalnya. Katakanlah file foo.txt
berisi 100 kejadian kata 'linux'.
Saya perlu mengganti 50 kejadian pertama saja.
text-processing
sed
awk
narendra-choudhary
sumber
sumber
Jawaban:
Bagian pertama di bawah ini menjelaskan penggunaan
sed
untuk mengubah kejadian-k pertama pada suatu garis. Bagian kedua memperluas pendekatan ini untuk mengubah hanya kejadian-k pertama dalam file, terlepas dari apa baris mereka muncul.Solusi berorientasi garis
Dengan sed standar, ada perintah untuk mengganti kemunculan kata ke-k pada sebuah baris. Jika
k
3, misalnya:Atau, seseorang dapat mengganti semua kejadian dengan:
Tidak satu pun dari ini yang Anda inginkan.
GNU
sed
menawarkan ekstensi yang akan mengubah kejadian k-th dan semuanya setelah itu. Jika k adalah 3, misalnya:Ini dapat digabungkan untuk melakukan apa yang Anda inginkan. Untuk mengubah 3 kejadian pertama:
di mana
\n
berguna di sini karena kita dapat yakin bahwa itu tidak pernah terjadi pada suatu garis.Penjelasan:
Kami menggunakan tiga
sed
perintah substitusi:s/\<old\>/\n/g4
Ini ekstensi GNU untuk menggantikan yang keempat dan semua kejadian berikutnya
old
dengan\n
.Fitur regex diperpanjang
\<
digunakan untuk mencocokkan awal kata dan\>
untuk mencocokkan akhir kata. Ini memastikan bahwa hanya kata-kata lengkap yang cocok. Regex yang diperluas membutuhkan-E
opsi untuksed
.s/\<old\>/new/g
Hanya tiga kejadian pertama yang
old
tersisa dan ini menggantikan semuanyanew
.s/\n/old/g
Kejadian keempat dan semua yang tersisa
old
digantikan dengan\n
pada langkah pertama. Ini mengembalikan mereka ke keadaan semula.Solusi non-GNU
Jika GNU sed tidak tersedia dan Anda ingin mengubah 3 kejadian pertama
old
menjadinew
, maka gunakan tigas
perintah:Ini bekerja dengan baik ketika
k
sejumlah kecil tetapi skala buruk ke besark
.Karena beberapa sed non-GNU tidak mendukung menggabungkan perintah dengan titik koma, setiap perintah di sini diperkenalkan dengan
-e
opsi sendiri . Mungkin juga perlu untuk memverifikasi bahwa Andased
mendukung simbol batas kata,\<
dan\>
.Solusi berorientasi file
Kita dapat meminta sed untuk membaca seluruh file dan kemudian melakukan penggantian. Misalnya, untuk mengganti tiga kejadian pertama
old
menggunakan sed gaya BSD:Perintah sed
H;1h;$!d;x
membaca seluruh file di.Karena di atas tidak menggunakan ekstensi GNU, itu harus bekerja pada BSD (OSX) sed. Perhatikan, pikirkan, bahwa pendekatan ini membutuhkan
sed
yang dapat menangani garis panjang. GNUsed
seharusnya baik-baik saja. Mereka yang menggunakan versi non-GNUsed
harus menguji kemampuannya untuk menangani antrean panjang.Dengan sed GNU, kita dapat lebih lanjut menggunakan
g
trik yang dijelaskan di atas, tetapi dengan\n
diganti dengan\x00
, untuk mengganti tiga kejadian pertama:Pendekatan ini berskala juga
k
menjadi besar. Ini mengasumsikan, bahwa\x00
itu tidak ada dalam string asli Anda. Karena tidak mungkin untuk menempatkan karakter\x00
dalam string bash, ini biasanya merupakan asumsi yang aman.sumber
tr '\n' '|' < input_file | sed …
. Tetapi, tentu saja, itu mengubah seluruh input menjadi satu baris, dan beberapa sed non-GNU tidak dapat menangani garis panjang yang sewenang-wenang. (2) Anda berkata, "... di atas, string yang dikutip'|'
harus diganti oleh karakter apa pun, atau string karakter, ..." Tetapi Anda tidak dapat menggunakantr
untuk mengganti karakter dengan string (panjang> 1). (3) Dalam contoh terakhir Anda, Anda katakan-e 's/\<old\>/new/' -e 's/\<old\>/w/' | tr '\000' '\n'\>/new
. Ini sepertinya salah ketik untuk-e 's/\<old\>/new/' -e 's/\<old\>/new/' -e 's/\<old\>/new/' | tr '\000' '\n'
.Menggunakan Awk
Perintah awk dapat digunakan untuk mengganti N kejadian pertama kata dengan penggantian.
Perintah hanya akan menggantikan jika kata tersebut benar-benar cocok.
Dalam contoh di bawah ini, saya mengganti
27
kejadian pertamaold
dengannew
Menggunakan sub
Mengganti bidang secara manual
Melakukan pemeriksaan sebelumnya
HASIL
Misalnya
untuk
sumber
$i
bitnya, sudah diedit, terima kasih :)Katakanlah Anda ingin mengganti hanya tiga contoh pertama dari string ...
catatan: di atas kemungkinan tidak akan berfungsi dengan komentar yang disematkan
... atau dalam contoh kasus saya, dari '1' ...
KELUARAN:
Di sana saya menggunakan dua teknik penting. Di tempat pertama setiap kemunculan
1
pada satu baris diganti dengan\n1
. Dengan cara ini, ketika saya melakukan penggantian rekursif berikutnya, saya bisa pastikan untuk tidak mengganti kejadian dua kali jika string pengganti saya berisi string pengganti saya. Misalnya, jika saya gantihe
denganhey
itu masih akan berfungsi.Saya melakukan ini seperti:
Kedua, saya menghitung penggantian dengan menambahkan karakter ke
h
ruang lama untuk setiap kejadian. Begitu saya mencapai tiga tidak ada lagi terjadi. Jika Anda menerapkan ini pada data Anda dan mengubah\{3\}
ke penggantian total yang Anda inginkan dan/\n1/
alamat untuk apa pun yang Anda ingin ganti, Anda harus mengganti hanya sebanyak yang Anda inginkan.Saya hanya melakukan semua
-e
hal untuk dibaca. POSIXly Dapat ditulis seperti ini:Dan dengan GNU
sed
:Ingat juga bahwa
sed
ini berorientasi garis - tidak membaca di seluruh file dan kemudian mencoba untuk mengulanginya seperti yang sering terjadi pada editor lain.sed
sederhana dan efisien. Yang mengatakan, sering kali nyaman untuk melakukan sesuatu seperti berikut:Berikut adalah fungsi shell kecil yang membundelnya menjadi perintah yang dieksekusi sederhana:
Maka dengan itu saya bisa melakukan:
... dan dapatkan ...
...atau...
...mendapatkan...
... atau, untuk mencocokkan contoh Anda (dengan urutan yang lebih kecil) :
sumber
Alternatif singkat di Perl:
Ubah nilai `$ n $ sesuai keinginan Anda.
Bagaimana itu bekerja:
new
untukold
(s/old/new/
) dan kapan pun bisa, itu akan menambahkan variabel$i
(++$i
).1 while ...
) selama itu telah membuat kurang dari$n
total substitusi dan dapat membuat setidaknya satu substitusi pada baris itu.sumber
Gunakan loop shell dan
ex
!Ya, ini agak konyol.
;)
Catatan: Ini mungkin gagal jika ada kurang dari 50 contoh
old
dalam file. (Saya belum mengujinya.) Jika demikian, itu akan membuat file tidak dimodifikasi.Lebih baik lagi, gunakan Vim.
Penjelasan:
sumber
Solusi sederhana, tetapi tidak terlalu cepat adalah untuk mengulang perintah yang dijelaskan dalam /programming/148451/how-to-use-sed-to-replace-only-the-first-occurrence-in-a -mengajukan
Perintah sed khusus ini mungkin hanya berfungsi untuk GNU sed dan jika newword bukan bagian dari oldword . Untuk non-GNU lihat di sini cara mengganti hanya pola pertama dalam file.
sumber
Dengan GNU
awk
Anda dapat mengatur pemisah rekamanRS
ke kata yang akan diganti dibatasi oleh batas kata. Maka itu adalah kasus pengaturan pemisah rekaman pada output ke kata pengganti untukk
catatan pertama sambil mempertahankan pemisah rekaman asli untuk sisanya.ATAU
sumber