Saya perlu secara rekursif mencari string yang ditentukan dalam semua file dan subdirektori dalam direktori dan mengganti string ini dengan string lain.
Saya tahu bahwa perintah untuk menemukannya mungkin terlihat seperti ini:
grep 'string_to_find' -r ./*
Tetapi bagaimana saya bisa mengganti setiap instance string_to_find
dengan string lain?
sed -i 's/.*substring.*/replace/'
sed -i 's/\(.*\)substring\(.*\)/\1replace\2/'
Jawaban:
Pilihan lain adalah menggunakan find dan kemudian melewati sed.
sumber
-i
diperlukan. Misalnya,find /path/to/files -type f -exec sed -i "" "s/oldstring/new string/g" {} \;
Bagaimanapun, memberikan string kosong masih membuat file cadangan tidak seperti yang dijelaskan dalam manual ...-i ""
untuk OS X. Ini berfungsi sebaliknya.CRLF
keLF
pada Windows.Saya mendapat jawabannya.
sumber
grep
dan sekali lagi dengansed
. Menggunakanfind
metode lebih efisien tetapi metode yang Anda sebutkan ini berfungsi.sed -i 's/str1/str2/g'
agarsed -i "" 's/str1/str2/g'
ini berfungsi.grep
memeriksa semua file dansed
hanya memindai file yang cocokgrep
. Denganfind
metode di jawaban lain,find
pertama-tama daftar semua file, dan kemudiansed
akan memindai semua file dalam direktori itu. Jadi metode ini belum tentu lebih lambat, tergantung pada berapa banyak kecocokan yang ada dan perbedaan kecepatan pencarian antarased
,grep
danfind
.Anda bahkan dapat melakukannya seperti ini:
Contoh
Ini akan mencari string ' windows ' di semua file relatif terhadap direktori saat ini dan mengganti ' windows ' dengan ' linux ' untuk setiap kemunculan string di setiap file.
sumber
grep
hanya berguna jika ada file yang tidak boleh dimodifikasi. Menjalankansed
semua file akan memperbarui tanggal modifikasi file tetapi membiarkan konten tidak berubah jika tidak ada kecocokan.-i
, saya yakinsed
mengubah waktu file dari setiap file yang disentuhnya, meskipun isinya tidak berubah.sed
Juga mengonversi akhiran baris. Saya tidak menggunakansed
Windows dalam repo Git karena semuaCRLF
diubah menjadiLF
.Ini bekerja paling baik untuk saya di OS X:
Sumber: http://www.praj.com.au/post/23691181208/grep-replace-text-string-in-files
sumber
ag "search" -l -r . | sort | uniq | xargs perl -e 's/search/replace' -pi
sort -u
genap ini? Dalam keadaan apa yang Anda harapkangrep -rl
untuk menghasilkan nama file yang sama dua kali?Solusi lain mencampur sintaks regex. Untuk menggunakan perl / pola PCRE untuk kedua pencarian dan mengganti, dan hanya file proses pencocokan, karya ini cukup baik:
di mana
match1
danmatch2
biasanya identik tetapimatch1
dapat disederhanakan untuk menghapus fitur yang lebih canggih yang hanya relevan dengan substitusi, misalnya menangkap grup.Terjemahan:
grep
secara rekursif dan daftar file yang cocok dengan pola PCRE ini, dipisahkan oleh nul untuk melindungi karakter khusus apa pun dalam namafile, lalu pipa nama filexargs
yang mengharapkan daftar yang dipisahkan nul, tetapi tidak akan melakukan apa pun jika tidak ada nama yang diterima, danperl
untuk mengganti garis tempat pertandingan ditemukan.Tambahkan
I
sakelargrep
untuk mengabaikan file biner. Untuk case-sensitive matching, dropi
beralih darigrep
, dani
bendera yang melekat pada ekspresi substitusi, tetapi tidak dengani
mengaktifkanperl
itu sendiri.sumber
find2perl
yang dikirimkan dengan Perl yang melakukan hal semacam ini tanpaxargs
tipu daya.find
tidak mencari konten file, dan intinya adalah hanya memproses file yang cocok tanpa menulis program Perl.Biasanya tidak dengan grep, melainkan dengan
sed -i 's/string_to_find/another_string/g'
atauperl -i.bak -pe 's/string_to_find/another_string/g'
.sumber
Berhati-hatilah saat menggunakan
find
dansed
dalam repo git! Jika Anda tidak mengecualikan file biner Anda bisa berakhir dengan kesalahan ini:Untuk mengatasi kesalahan ini, Anda harus mengembalikan
sed
dengan menggantinew_string
dengan Andaold_string
. Ini akan mengembalikan string yang diganti, sehingga Anda akan kembali ke awal masalah.Cara yang benar untuk mencari string dan menggantinya adalah dengan melompat
find
dan menggunakannyagrep
sebagai gantinya untuk mengabaikan file biner:Kredit untuk @hobs
sumber
Inilah yang akan saya lakukan:
ini akan mencari semua file yang mengandung
filename
nama file di bawah/path/to/dir
, daripada untuk setiap file yang ditemukan, mencari baris dengansearchstring
dan gantiold
dengannew
.Padahal jika Anda ingin menghilangkan mencari file tertentu dengan
filename
string dalam nama file, daripada cukup lakukan:Ini akan melakukan hal yang sama di atas, tetapi untuk semua file yang ditemukan di bawah
/path/to/dir
.sumber
Pilihan lain adalah menggunakan perl dengan globstar.
Mengaktifkan
shopt -s globstar
di.bashrc
(atau di mana pun) Anda memungkinkan**
pola gumpalan untuk mencocokkan semua sub-direktori dan file secara rekursif.Dengan demikian menggunakan
perl -pXe 's/SEARCH/REPLACE/g' -i **
rekursif akan menggantikanSEARCH
denganREPLACE
.Itu
-X
flag mengatakan perl untuk "menonaktifkan semua peringatan" - yang berarti bahwa itu tidak akan mengeluh tentang direktori.The globstar juga memungkinkan Anda untuk melakukan hal-hal seperti
sed -i 's/SEARCH/REPLACE/g' **/*.ext
jika Anda ingin menggantiSEARCH
denganREPLACE
semua file anak dengan ekstensi.ext
.sumber
grep
dansed
.