Temukan dan ganti teks dalam file menggunakan perintah

Jawaban:

1053
sed -i 's/original/new/g' file.txt

Penjelasan:

  • sed = Streaming Editor
  • -i = di tempat (mis. menyimpan kembali ke file asli)
  • String perintah:

    • s = perintah pengganti
    • original = ekspresi reguler yang menggambarkan kata yang akan diganti (atau hanya kata itu sendiri)
    • new = teks untuk menggantikannya
    • g = global (mis. ganti semua dan bukan hanya kejadian pertama)
  • file.txt = nama file

cscarney
sumber
3
@ Akiva Jika Anda memasukkan regex karakter khusus dalam pencarian Anda sedakan cocok dengan mereka. Tambahkan -rbendera jika Anda ingin menggunakan RE yang diperluas sebagai gantinya.
cscarney
32
@ mcExchange Jika khusus /karakter yang harus Anda cocokkan, Anda bisa menggunakan beberapa karakter lain sebagai pemisah (mis 's_old/text_new/text_g'.). Jika tidak, Anda dapat meletakkan \ sebelum apa pun $ * . [ \ ^untuk mendapatkan karakter literal.
cscarney
3
@ BrianZ Sejauh menyangkut sistem file, output dari sed adalah file baru dengan nama yang sama. Itu salah satu bug yang sering dilaporkan dan bukan bug
cscarney
17
Perintah OSX sed -i '.bak' 's/original/new/g' file.txtjuga dapat dijalankan dengan ekstensi panjang nol sed -i '' 's/original/new/g' file.txt, yang tidak akan menghasilkan cadangan.
Kirk
20
Pengguna MacOS harus menambahkan '' "setelah -i sebagai parameter untuk -i ed.gs/2016/01/26/os-x-sed-invalid-command-code sehingga file akan ditimpa.
geoyws
32

Ada sejumlah cara berbeda untuk melakukan ini. Salah satunya menggunakan seddan Regex. SED adalah Editor Stream untuk memfilter dan mengubah teks. Salah satu contohnya adalah sebagai berikut:

marco@imacs-suck: ~$ echo "The slow brown unicorn jumped over the hyper sleeping dog" > orly
marco@imacs-suck: ~$ sed s/slow/quick/ < orly > yarly
marco@imacs-suck: ~$ cat yarly
The quick brown unicorn jumped over the hyper sleeping dog

Cara lain yang mungkin lebih masuk akal daripada < strindan > stroutadalah dengan pipa!

marco@imacs-suck: ~$ cat yarly | sed s/unicorn/fox/ | sed s/hyper/lazy/ > nowai
marco@imacs-suck: ~$ cat nowai 
The quick brown fox jumped over the lazy sleeping dog
Marco Ceppi
sumber
6
perhatikan catdi cat file | sed '...'tidak perlu. Anda bisa langsung bilang sed '...' file.
fedorqui
1
Memang ini bisa dikurangi lebih jauh: sed -i'.bak' -e 's/unicorn/fox/g;s/hyper/brown/g' yarlyakan mengambil file yarly dan melakukan 2 perubahan di tempat sambil membuat cadangan. Menggunakan time bash -c "$COMMAND"waktu itu menunjukkan bahwa versi ini ~ 5 kali lebih cepat.
pbhj
23

Ada banyak cara untuk mencapainya. Bergantung pada kerumitan apa yang ingin dicapai dengan penggantian string, dan tergantung pada alat yang akrab dengan pengguna, beberapa metode mungkin lebih disukai daripada yang lain.

Dalam jawaban ini saya menggunakan input.txtfile sederhana , yang dapat Anda gunakan untuk menguji semua contoh yang disediakan di sini. Isi file:

roses are red , violets are blue
This is an input.txt and this doesn't rhyme

PESTA

Bash sebenarnya tidak dimaksudkan untuk pemrosesan teks, tetapi penggantian sederhana dapat dilakukan melalui ekspansi parameter , khususnya di sini kita dapat menggunakan struktur sederhana ${parameter/old_string/new_string}.

#!/bin/bash
while IFS= read -r line
do
    case "$line" in
       *blue*) printf "%s\n" "${line/blue/azure}" ;;
       *) printf "%s\n" "$line" ;;
    esac
done < input.txt

Skrip kecil ini tidak melakukan penggantian di tempat, artinya Anda harus menyimpan teks baru ke file baru, dan menyingkirkan file lama, atau mv new.txt old.txt

Catatan: jika Anda ingin tahu mengapa while IFS= read -r ; do ... done < input.txtdigunakan, ini pada dasarnya cara shell membaca baris per baris. Lihat ini untuk referensi.

AWK

AWK, sebagai utilitas pemrosesan teks, cukup sesuai untuk tugas tersebut. Ia dapat melakukan penggantian sederhana dan yang lebih maju berdasarkan pada ekspresi reguler . Ini menyediakan dua fungsi: sub()dan gsub(). Yang pertama hanya menggantikan kejadian pertama, sedangkan yang kedua - menggantikan kejadian di seluruh string. Misalnya, jika kita memiliki string one potato two potato, ini akan menjadi hasilnya:

$ echo "one potato two potato" | awk '{gsub(/potato/,"banana")}1'
one banana two banana

$ echo "one potato two potato" | awk '{sub(/potato/,"banana")}1'                                      
one banana two potato 

AWK dapat mengambil file input sebagai argumen, jadi melakukan hal yang sama dengannya input.txt, akan mudah:

awk '{sub(/blue/,"azure")}1' input.txt

Bergantung pada versi AWK yang Anda miliki, mungkin saja ada atau tidak ada pengeditan di tempat, maka praktik yang biasa dilakukan adalah menyimpan dan mengganti teks baru. Misalnya sesuatu seperti ini:

awk '{sub(/blue/,"azure")}1' input.txt > temp.txt && mv temp.txt input.txt

SED

Sed adalah editor baris. Itu juga menggunakan ekspresi reguler, tetapi untuk penggantian sederhana itu cukup untuk melakukan:

sed 's/blue/azure/' input.txt

Apa yang baik tentang alat ini adalah memiliki pengeditan di tempat, yang dapat Anda aktifkan dengan -iflag.

Perl

Perl adalah alat lain yang sering digunakan untuk pemrosesan teks, tetapi merupakan bahasa tujuan umum, dan digunakan dalam jaringan, administrasi sistem, aplikasi desktop, dan banyak tempat lainnya. Ini meminjam banyak konsep / fitur dari bahasa lain seperti C, sed, awk, dan lainnya. Substitusi sederhana dapat dilakukan sebagai berikut:

perl -pe 's/blue/azure/' input.txt

Seperti sed, perl juga memiliki flag -i.

Python

Bahasa ini sangat fleksibel dan juga digunakan dalam berbagai aplikasi. Ini memiliki banyak fungsi untuk bekerja dengan string, di antaranya adalah replace(), jadi jika Anda memiliki variabel like var="Hello World", Anda bisa melakukannyavar.replace("Hello","Good Morning")

Cara sederhana untuk membaca file dan mengganti string di dalamnya adalah sebagai berikut:

python -c "import sys;lines=sys.stdin.read();print lines.replace('blue','azure')" < input.txt

Namun, dengan Python, Anda juga perlu meng-output ke file baru, yang juga dapat Anda lakukan dari dalam skrip itu sendiri. Misalnya, ini yang sederhana:

#!/usr/bin/env python
import sys
import os
import tempfile

tmp=tempfile.mkstemp()

with open(sys.argv[1]) as fd1, open(tmp[1],'w') as fd2:
    for line in fd1:
        line = line.replace('blue','azure')
        fd2.write(line)

os.rename(tmp[1],sys.argv[1])

Script ini disebut dengan input.txtargumen baris perintah. Perintah yang tepat untuk menjalankan skrip python dengan argumen command-line adalah

 $ ./myscript.py input.txt

atau

$ python ./myscript.py input.txt

Tentu saja, pastikan itu ./myscript.pyada di direktori kerja Anda saat ini dan untuk cara pertama, pastikan direktori tersebut dapat dieksekusichmod +x ./myscript.py

Python juga dapat memiliki ekspresi reguler, khususnya, ada remodul, yang memiliki re.sub()fungsi, yang dapat digunakan untuk penggantian yang lebih maju.

Sergiy Kolodyazhnyy
sumber
1
Kompilasi yang bagus! Cara lain yang mungkin tidak disebutkan di sini adalah menggunakan trperintah di unix
Tapajit Dey
1
@TapajitDey Ya, tr adalah alat hebat lainnya, tetapi perhatikan bahwa itu untuk mengganti sekumpulan karakter (misalnya tr abc cdeakan diterjemahkan amenjadi c, buntuk d. Ini sedikit berbeda dari mengganti seluruh kata dengan sedataupython
Sergiy Kolodyazhnyy
22

Anda dapat menggunakan Vim dalam mode Ex:

ex -s -c '%s/OLD/NEW/g|x' file
  1. % pilih semua garis

  2. s pengganti

  3. g ganti semua instance di setiap baris

  4. x tulis jika telah dilakukan perubahan (sudah) dan keluar

Steven Penny
sumber
21

Melalui perintah gsub awk,

awk '{gsub(/pattern/,"replacement")}' file

Contoh:

awk '{gsub(/1/,"0");}' file

Dalam contoh di atas, semua 1 digantikan oleh 0 terlepas dari kolom di mana ia berada.


Jika Anda ingin melakukan penggantian pada kolom tertentu, maka lakukan seperti ini,

awk '{gsub(/pattern/,"replacement",column_number)}' file

Contoh:

awk '{gsub(/1/,"0",$1);}' file

Ia menggantikan 1 dengan 0 pada kolom pertama saja.

Melalui Perl,

$ echo 'foo' | perl -pe 's/foo/bar/g'
bar
Avinash Raj
sumber
Saya menggunakan ini pada terminal MacOS dan tidak melakukan apa pun ...
Jim
Diuji di Alpine Linux (dalam wadah Docker) dan tidak mendapat hasil
Salathiel Genèse
@ SalathielGenèse apa yang ingin Anda capai?
Avinash Raj
Saya menonton file dengan di inotifywaitbawah shenv, dan melaporkan data dalam format CSV (karena format khusus bersifat buggy). Saya kemudian menemukan tidak ada cara sederhana untuk menangani dokumen CSV dalam skrip shell ... Dan saya ingin itu sangat ringan. Jadi saya memulai skrip yang cukup sederhana untuk mem-parsing dan melaporkan CSV. Saya membaca spesifikasi CSV dan memperhatikannya lebih rumit dari yang saya harapkan dan mendukung nilai multiline yang dibungkus dengan tanda kutip ganda. Saya mengandalkan sedtokenization tetapi segera menyadari bahwa apa pun yang seddisebut multilines hingga dua baris. Lalu bagaimana jika salah satu nilai CSV saya menjangkau lebih dari dua baris?
Salathiel Genèse
lebih baik untuk menanyakan masalah Anda sebagai pertanyaan.
Avinash Raj
8

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 bagi Anda -i -euntuk mencari / mengganti. Jika ya -ie, Anda membuat cadangan setiap file dengan huruf 'e' ditambahkan.

Chaminda Bandara
sumber
2

Anda bisa melakukan ini:

locate <part of filaname to locate> | xargs sed -i -e "s/<Old text>/<new text>/g" 

Contoh: untuk mengganti semua kejadian [logdir ',' '] (tanpa []) dengan [logdir', os.getcwd ()] di semua file yang merupakan hasil dari perintah loc, lakukan:

ex1:

locate tensorboard/program.py | xargs sed -i -e "s/old_text/NewText/g"

ex2:

locate tensorboard/program.py | xargs sed -i -e "s/logdir', ''/logdir', os.getcwd()/g"

di mana [tensorboard / program.py] adalah file untuk dicari

Nguyễn Tuấn Anh
sumber
Hai. Pilihan string Anda ( logdir', ''-> /logdir', os.getcwd()) membuat jawaban ini sulit untuk diurai. Juga, ada baiknya menentukan bahwa jawaban Anda pertama-tama menemukan file yang akan digunakan, karena itu bukan bagian dari pertanyaan.
mwfearnley
Hai, jawaban ini adalah pencarian dan ganti semua jika ditemukan <teks lama> dalam file.
Nguyễn Tuấn Anh
Saya memilih jawaban ini untuk semua yang mereka gunakan tensorboard dalam keras, yang ingin mengubah perintah dari: tensorboard --logdir = '/ path / ke / log / folder /' untuk menggunakan: tensorboard saja, ketika tinggal di folder log. ini sangat mudah
Nguyễn Tuấn Anh