Kiat: Jangan lakukan yang di bawah ini di pohon checkout svn ... itu akan menimpa file folder ajaib .svn.
J. Polfer 8-10
7
Ya Tuhan, inilah yang baru saja saya lakukan. Tapi itu berhasil dan sepertinya tidak ada salahnya. Apa hal terburuk yang bisa terjadi?
J. Katzwinkel
5
@ J.Katzwinkel: paling tidak, itu dapat merusak checksum, yang dapat merusak repositori Anda.
ninjagecko
3
Kiat cepat untuk semua orang yang menggunakan sed: Ini akan menambahkan trailing baris baru ke file Anda. Jika Anda tidak menginginkannya, pertama-tama lakukan pencarian-ganti yang tidak cocok dengan apa pun, dan lakukan itu untuk git. Kemudian lakukan yang asli. Kemudian rebase secara interaktif dan hapus yang pertama.
funroll
5
Anda dapat mengecualikan direktori, seperti git, dari hasil dengan menggunakan -path ./.git -prune -odi find . -path ./.git -prune -o -type f -name '*matchThisText*' -print0sebelum pipa ke xargs
devinbost
Jawaban:
851
find /home/www \( -type d -name .git -prune \) -o -type f -print0 | xargs -0 sed -i 's/subdomainA\.example\.com/subdomainB.example.com/g'
-print0memberitahu finduntuk mencetak setiap hasil yang dipisahkan oleh karakter nol, daripada baris baru. Jika direktori Anda memiliki file dengan baris baru di namanya, ini masih memungkinkan xargsbekerja pada nama file yang benar.
\( -type d -name .git -prune \)adalah ekspresi yang sepenuhnya melompati semua direktori yang bernama .git. Anda dapat dengan mudah mengembangkannya, jika Anda menggunakan SVN atau memiliki folder lain yang ingin Anda pertahankan - cukup cocokkan dengan lebih banyak nama. Ini kira-kira setara dengan -not -path .git, tetapi lebih efisien, karena daripada memeriksa setiap file dalam direktori, itu melompati seluruhnya. The -osetelah itu diperlukan karena cara -prunebenar-benar bekerja.
Pada OSX Anda mungkin mengalami sed: 1: "...": invalid command code .masalah. Tampaknya opsi -i mengharapkan ekstensi dan mem-parsing 's/../...'perintah keluar. Solusi: berikan ekstensi '' ke -i opsi seperti sed -i '' 's/....
Robert Lujo
6
Catatan: jika Anda menggunakan ini di direktori dan bertanya-tanya mengapa svn sttidak menunjukkan perubahan, itu karena Anda telah memodifikasi file di direktori .svn juga! Gunakan find . -maxdepth 1 -type f -print0 | xargs -0 sed -i 's/toreplace/replaced/g'sebagai gantinya.
ACK_stoverflow
57
Juga, berhati-hatilah jika Anda berada di git repo. Saya pikir saya pintar dengan menguji ini pada cabang yang jelas sehingga saya bisa kembali jika melakukan sesuatu yang buruk, tetapi malah merusak indeks git saya.
Ciryon
13
Gunakan ini grep -r 'hello' -l --null . | xargs -0 sed -i 's#hello#world#g'untuk menghindari mengedit file yang tidak terkait (sed mungkin mengubah pengkodean file).
caiguanhao
6
"Tapi malah merusak indeks git saya." Jangan terlalu khawatir tentang hal ini yang bisa Anda lakukan find .git ... | ... 'sed -i s/(the opposite from before)/g'untuk memperbaiki indeks git Anda
Massey101
259
Catatan : Jangan jalankan perintah ini pada folder termasuk git repo - perubahan ke. Git dapat merusak indeks git Anda.
find /home/www/-type f -exec \
sed -i 's/subdomainA\.example\.com/subdomainB.example.com/g'{}+
Dibandingkan dengan jawaban lain di sini, ini lebih sederhana daripada kebanyakan dan menggunakan sed bukan perl, yang merupakan pertanyaan awal.
Perhatikan bahwa jika Anda menggunakan BSD sed (termasuk di Mac OS X) Anda harus memberikan string kosong secara eksplisit ke -iopsi sed . yaitu: sed -i '' 's/original/replacement/g'
Nathan Craike
2
@JohnZwinck Kesalahan saya, melewatkan +. Anehnya, solusi Nikita berjalan lebih cepat untuk saya.
Sam
6
@ AoeAoe: Sangat +mengurangi jumlah sedproses yang dihasilkan. Ini lebih efisien.
John Zwinck
4
Bagaimana saya bisa melakukan ini dengan aman di folder dengan git repo?
Hatshepsut
20
Ini aman untuk mengeksekusi pada folder yang berisi repo git jika Anda mengecualikan repo dari hasil find Anda: find . -not -path '*/\.git*' -type f ....
Dale Anderson
211
Cara paling sederhana bagi saya adalah
grep -rl oldtext .| xargs sed -i 's/oldtext/newtext/g'
Ini bekerja sangat baik, ketika Anda perlu mengecualikan direktori, suka dengan .svn. Misalnya:grep -rl oldtext . --exclude-dir=.svn | xargs sed -i 's/oldtext/newtext/g'
phyatt
11
brew install gnu-seddan gunakan gsedpada OSX untuk menghindari dunia kesakitan.
P i
1
orang-orang menyenangkan perhatian, jika proyek Anda git berversi, gunakan ini sebagai gantinya: git grep -rl oldtext . | xargs sed -i 's/oldtext/newtext/g'. itu tidak baik sama sekali untuk mendapatkan .gitdir Anda
Paolo
61
Semua triknya hampir sama, tapi saya suka yang ini:
find <mydir>-type f -exec sed -i 's/<string1>/<string2>/g'{}+
find <mydir>: lihat di direktori.
-type f:
File bertipe: file biasa
-exec command {} +:
Varian aksi -exec ini menjalankan perintah yang ditentukan pada file yang dipilih, tetapi baris perintah dibangun dengan menambahkan setiap nama file yang dipilih di akhir; jumlah total doa perintah akan jauh lebih sedikit daripada jumlah file yang cocok. Baris perintah dibangun dengan cara yang sama seperti xargs membangun baris perintahnya. Hanya satu instance dari `{} 'diizinkan dalam perintah. Perintah dijalankan di direktori awal.
@ user2284570 dengan -exec? Cobalah untuk mengatur path ke executable daripada nama alat.
1515
@ I159: Tidak: kecualikan binari yang dapat dieksekusi (tetapi sertakan skrip shell) .
user2284570
8
@ I159 Bukankah jawaban ini identik dengan John Zwinck ?
Reinstate Monica Please
1
@ user2284570 Konsep "file biner" tidak sepenuhnya didefinisikan dengan baik. Anda dapat menggunakan fileperintah untuk mencoba menentukan jenis file masing-masing, tetapi variasi serampangan dalam outputnya mungkin sedikit membingungkan. Opsi -I(alias --mime) agak membantu, atau --mime-typejika Anda memilikinya. Bagaimana tepatnya untuk memperbaiki ini satu-liner rapi untuk melakukan ini sayangnya di luar jangkauan untuk kotak komentar kecil ini. Mungkin memposting pertanyaan terpisah jika Anda butuh bantuan? (Mungkin tambahkan komentar dengan tautan di sini.)
tripleee
1
jawaban paling bersih! terima kasih sobat
jukerok
39
cd /home/www && find .-type f -print0 |
xargs -0 perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g'
Saya ingin tahu, apakah ada alasan untuk menggunakan -print0dan xargsbukannya -execatau -execdir?
Philipp
4
Ada: dari "man find": Perintah yang ditentukan dijalankan sekali untuk setiap file yang cocok. Yaitu, jika ada 2000 file di / home / www, maka 'find ... -exec ...' akan menghasilkan 2000 doa perl; sedangkan 'temukan ... | xargs ... 'hanya akan memanggil perl sekali atau dua kali (dengan asumsi ARG_MAX sekitar 32K dan panjang rata-rata nama file 20).
Dipekerjakan Rusia
2
@ Dipekerjakan Rusia: itu sebabnya Anda akan menggunakan find -exec command {} +- itu memang menghindari pemanggilan perintah yang berlebihan seperti xargs, tetapi tanpa proses terpisah.
John Zwinck
2
Di platform mana? Solusi xargs adalah portable, doa "ajaib" dari "find ... -exec" yang tidak memanggil subproses untuk setiap file yang ditemukan bukan.
Dipekerjakan Rusia
4
@EmployedRussian, find -exec ... {} +telah ditentukan POSIX sejak 2006.
CATATAN : Jika ada terlalu banyak file untuk diproses, Anda akan mendapatkannya Argument list too long. Solusi - penggunaan find -execatau xargssolusi yang dijelaskan di atas.
The workaroundharus sintaks yang lebih disukai dalam semua kasus.
Reinstate Monica Please
1
Masalah dengan substitusi perintah $(find...)adalah bahwa tidak ada cara bagi shell untuk menangani nama file dengan spasi putih atau karakter meta shell lainnya di dalamnya. Jika Anda tahu ini bukan masalah, pendekatan ini baik-baik saja; tetapi kami memiliki terlalu banyak pertanyaan di mana orang tidak diberi peringatan tentang masalah ini, atau tidak memahami peringatan itu.
Ide bagus jika bekerja di dalam git repo karena Anda tidak mengambil risiko menimpa .git / konten (seperti yang dilaporkan dalam komentar untuk jawaban lain).
mahemoff
1
Terima kasih, saya menggunakannya sebagai bash function refactor() { echo "Replacing $1 by $2 in all files in this git repository." git grep -lz $1| xargs -0 perl -i'' -pE "s/$1/$2/g" }Usage, misalnya untuk mengganti 'kata' dengan 'pedang': refactor word swordlalu verifikasi dengan apa itu git diff.
Paul Rougieux
16
Untuk mengurangi file secara rekursif sed, Anda bisa grepmenggunakan string misalnya:
grep -rl <oldstring>/path/to/folder | xargs sed -i s^<oldstring>^<newstring>^g
Jika Anda menjalankan, man grepAnda akan melihat bahwa Anda juga dapat menentukan --exlude-dir="*.git"bendera jika Anda ingin menghilangkan pencarian melalui direktori .git, menghindari masalah indeks git seperti yang orang lain tunjukkan dengan sopan.
Menuntun Anda ke:
grep -rl --exclude-dir="*.git"<oldstring>/path/to/folder | xargs sed -i s^<oldstring>^<newstring>^g
Bijaksana untuk menggunakan git-grep's -zpilihan bersama dengan xargs -0.
gniourf_gniourf
git grepjelas hanya masuk akal dalam gitrepo. Pengganti umum akan menjadi grep -r.
tripleee
@gniourf_gniourf Bisakah Anda jelaskan?
Petr Peller
2
@PetrPeller: with -z, git-grepakan memisahkan bidang output dengan null byte, bukan baris baru; dan dengan -0, xargsakan membaca input yang dipisahkan oleh byte nol, bukannya kosong (dan tidak melakukan hal-hal aneh dengan tanda kutip). Jadi jika Anda tidak ingin perintah untuk istirahat jika nama file mengandung spasi, tanda kutip atau karakter lucu lainnya, perintahnya adalah: git grep -z -l 'original_text' | xargs -0 sed ....
gniourf_gniourf
10
find /home/www/-type f -exec perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g'{}+
find /home/www/ -type f akan mencantumkan semua file di / home / www / (dan subdirektori-nya). Bendera "-exec" memberi tahu find untuk menjalankan perintah berikut pada setiap file yang ditemukan.
adalah perintah yang dijalankan pada file (banyak sekaligus). The {}akan digantikan oleh nama file. Di +akhir perintah memberitahu finduntuk membangun satu perintah untuk banyak nama file.
Per findhalaman manual: "Baris perintah dibangun dengan cara yang sama seperti xargs membangun baris perintahnya."
Dengan demikian dimungkinkan untuk mencapai tujuan Anda (dan menangani nama file yang mengandung spasi) tanpa menggunakan xargs -0, atau -print0.
Ack-grep sangat efisien dalam menemukan file yang relevan. Perintah ini menggantikan ~ 145.000 file dengan mudah, sedangkan yang lain memakan waktu sangat lama sehingga saya tidak bisa menunggu sampai selesai.
Metode langsung jika Anda perlu mengecualikan direktori ( --exclude-dir=.svn) dan juga mungkin memiliki nama file dengan spasi (menggunakan 0Byte dengan grep -Zdanxargs -0
grep -rlZ oldtext .--exclude-dir=.svn | xargs -0 sed -i 's/oldtext/newtext/g'
grep -lr 'subdomainA.example.com' | while read file; do sed -i "s/subdomainA.example.com/subdomainB.example.com/g" "$file"; done
Saya kira sebagian besar orang tidak tahu bahwa mereka dapat menyalurkan sesuatu ke dalam file "sambil membaca" dan itu menghindari argumen -print0 jahat, sementara ruang presevering dalam nama file.
Lebih lanjut menambahkan echosebelum sed memungkinkan Anda untuk melihat file apa yang akan berubah sebelum benar-benar melakukannya.
Alasannya -print0berguna adalah bahwa ia menangani kasus-kasus yang while readtidak bisa ditangani - baris baru adalah karakter yang valid dalam nama file Unix, jadi agar kode Anda benar-benar kuat, perlu juga menangani nama file seperti itu. (Juga, Anda ingin read -rmenghindari beberapa perilaku warisan POSIX yang sial di read.)
tripleee
Juga, sedini adalah no-op jika tidak ada kecocokan, jadi grepitu tidak benar-benar diperlukan; meskipun ini adalah pengoptimalan yang berguna untuk menghindari menulis ulang file yang tidak mengandung kecocokan, jika Anda memiliki banyak, atau ingin menghindari memperbarui cap tanggal pada file yang tidak perlu.
tripleee
5
Anda dapat menggunakan awk untuk menyelesaikan ini seperti di bawah ini,
Bekerja pada MacO tanpa masalah! Semua sedperintah berbasis gagal ketika binari dimasukkan bahkan dengan pengaturan spesifik osx.
Jankapunkt
Hati-hati ... ini akan meledak jika ada file yang findkembali memiliki ruang dalam nama mereka! Ini jauh lebih aman untuk digunakan while read: stackoverflow.com/a/9612560/1938956
Soren Bjornstad
4
Coba ini:
sed -i 's/subdomainA/subdomainB/g'`grep -ril 'subdomainA' *`
Hai @RikHic, tip yang bagus - sedang memikirkan sesuatu seperti ini; sayangnya pemformatan di atas tidak berjalan dengan benar :) Jadi saya akan mencoba dengan tag pra (tidak berfungsi) - jadi dengan lolos dari backticks maka: sed -i 's/subdomainA/subdomainB/g'` grep -ril 'subdomainA' /home/www/*` - ini masih tidak terlihat terlalu bagus, tetapi seharusnya selamat dari copypaste :) Cheers!
sdaau
4
#!/usr/local/bin/bash -x
find */home/www -type f |while read files
do
sedtest=$(sed -n '/^/,/$/p'"${files}"| sed -n '/subdomainA/p')if["${sedtest}"]then
sed s'/subdomainA/subdomainB/'g "${files}">"${files}".tmp
mv "${files}".tmp "${files}"fidone
grep secara rekursif untuk string yang ingin Anda ganti di jalur tertentu, dan ambil hanya path lengkap dari file yang cocok. (itu akan menjadi $(grep 'string' 'pathname' -Rl).
(opsional) jika Anda ingin melakukan pra-backup file-file itu pada direktori terpusat mungkin Anda dapat menggunakan ini juga: cp -iv $(grep 'string' 'pathname' -Rl) 'centralized-directory-pathname'
setelah itu Anda dapat mengedit / mengganti sesuka hati dalam vimmengikuti skema yang mirip dengan yang disediakan pada tautan yang diberikan:
Sekolah yang agak tua tetapi ini bekerja pada OS X.
Ada beberapa trik:
• Hanya akan mengedit file dengan ekstensi di .slsbawah direktori saat ini
• .harus melarikan diri untuk memastikan sedtidak mengevaluasi mereka sebagai "karakter apa pun"
• ,digunakan sebagai sedpembatas sebagai ganti dari yang biasa/
Juga perhatikan ini untuk mengedit template Jinja untuk melewati variabledi jalur import(tapi ini di luar topik).
Pertama, verifikasi perintah sed Anda melakukan apa yang Anda inginkan (ini hanya akan mencetak perubahan ke stdout, itu tidak akan mengubah file):
for file in $(find .-name *.sls -type f);do echo -e "\n$file: "; sed 's,foo\.bar,foo/bar/\"+baz+\"/,g' $file;done
Edit perintah sed sesuai kebutuhan, setelah Anda siap untuk melakukan perubahan:
for file in $(find .-name *.sls -type f);do echo -e "\n$file: "; sed -i '''s,foo\.bar,foo/bar/\"+baz+\"/,g' $file;done
Catat -i ''dalam perintah sed , saya tidak ingin membuat cadangan dari file asli (seperti yang dijelaskan dalam In-place edit dengan sed pada OS X atau dalam komentar Robert Lujo di halaman ini).
plus satu untuk `'*. [c | cc | cp | cpp | m | mm | h]'`
FractalSpace
2
Inilah versi yang harus lebih umum daripada kebanyakan; itu tidak memerlukan find(menggunakan dugantinya), misalnya. Memang diperlukan xargs, yang hanya ditemukan di beberapa versi Plan 9 (seperti 9front)
du -a | awk -F' ''{ print $2 }'| xargs sed -i -e 's/subdomainA\.example\.com/subdomainB.example.com/g'
Jika Anda ingin menambahkan filter seperti ekstensi file gunakan grep:
du -a | grep "\.scala$"| awk -F' ''{ print $2 }'| xargs sed -i -e 's/subdomainA\.example\.com/subdomainB.example.com/g'
Ini memiliki beberapa masalah sial dengan mengutip serta membaca baris for.
tripleee
1
Jika Anda ingin menggunakan ini tanpa sepenuhnya menghancurkan repositori SVN Anda, Anda dapat memberi tahu 'find' untuk mengabaikan semua file tersembunyi dengan melakukan:
find . \( !-regex '.*/\..*' \) -type f -print0 | xargs -0 sed -i 's/subdomainA.example.com/subdomainB.example.com/g'
Tanda kurung tampaknya berlebihan. Ini sebelumnya memiliki kesalahan pemformatan yang membuatnya tidak dapat digunakan (rendering Markdown akan memakan beberapa karakter dari regex).
tripleee
1
Menggunakan kombinasi grepdansed
for pp in $(grep -Rl looking_for_string)do
sed -i 's/looking_for_string/something_other/g'"${pp}"done
@ tripleee Saya sedikit memodifikasi ini. Dalam hal ini output untuk perintah yang grep -Rl patterndihasilkan daftar file di mana polanya. File tidak dibaca dalam forlingkaran.
Pawel
Hah? Anda masih memiliki satu forlingkaran; jika ada nama file yang dikembalikan berisi spasi, itu tidak akan berfungsi dengan benar, karena shell tokenizes fordaftar argumen. Tapi kemudian Anda menggunakan variabel nama file tanpa tanda kutip di dalam loop, jadi itu akan pecah di sana jika Anda memperbaikinya. Mengoreksi bug yang tersisa ini akan membuat Anda identik dengan jawaban @ MadMan2064.
tripleee
@ tripleee ya, itu benar, saya melewatkan ini.
Pawel
1
Untuk mengganti semua kejadian di repositori git, Anda dapat menggunakan:
git ls-files -z | xargs -0 sed -i 's/subdomainA\.example\.com/subdomainB.example.com/g'
Lihat Daftar file dalam repo git lokal? untuk opsi lain untuk membuat daftar semua file dalam repositori. The -zpilihan memberitahu git untuk memisahkan nama file dengan byte nol, yang menjamin bahwa xargs(dengan pilihan -0) dapat memisahkan nama file, bahkan jika mereka berisi spasi atau entah apa lagi.
-path ./.git -prune -o
difind . -path ./.git -prune -o -type f -name '*matchThisText*' -print0
sebelum pipa ke xargsJawaban:
-print0
memberitahufind
untuk mencetak setiap hasil yang dipisahkan oleh karakter nol, daripada baris baru. Jika direktori Anda memiliki file dengan baris baru di namanya, ini masih memungkinkanxargs
bekerja pada nama file yang benar.\( -type d -name .git -prune \)
adalah ekspresi yang sepenuhnya melompati semua direktori yang bernama.git
. Anda dapat dengan mudah mengembangkannya, jika Anda menggunakan SVN atau memiliki folder lain yang ingin Anda pertahankan - cukup cocokkan dengan lebih banyak nama. Ini kira-kira setara dengan-not -path .git
, tetapi lebih efisien, karena daripada memeriksa setiap file dalam direktori, itu melompati seluruhnya. The-o
setelah itu diperlukan karena cara-prune
benar-benar bekerja.Untuk informasi lebih lanjut, lihat
man find
.sumber
sed: 1: "...": invalid command code .
masalah. Tampaknya opsi -i mengharapkan ekstensi dan mem-parsing's/../...'
perintah keluar. Solusi: berikan ekstensi '' ke -i opsi sepertised -i '' 's/...
.svn st
tidak menunjukkan perubahan, itu karena Anda telah memodifikasi file di direktori .svn juga! Gunakanfind . -maxdepth 1 -type f -print0 | xargs -0 sed -i 's/toreplace/replaced/g'
sebagai gantinya.grep -r 'hello' -l --null . | xargs -0 sed -i 's#hello#world#g'
untuk menghindari mengedit file yang tidak terkait (sed mungkin mengubah pengkodean file).find .git ... | ... 'sed -i s/(the opposite from before)/g'
untuk memperbaiki indeks git AndaCatatan : Jangan jalankan perintah ini pada folder termasuk git repo - perubahan ke. Git dapat merusak indeks git Anda.
Dibandingkan dengan jawaban lain di sini, ini lebih sederhana daripada kebanyakan dan menggunakan sed bukan perl, yang merupakan pertanyaan awal.
sumber
-i
opsi sed . yaitu:sed -i '' 's/original/replacement/g'
+
mengurangi jumlahsed
proses yang dihasilkan. Ini lebih efisien.find . -not -path '*/\.git*' -type f ...
.Cara paling sederhana bagi saya adalah
sumber
-I
atau--binary-file=without-match
grep flag..svn
. Misalnya:grep -rl oldtext . --exclude-dir=.svn | xargs sed -i 's/oldtext/newtext/g'
brew install gnu-sed
dan gunakangsed
pada OSX untuk menghindari dunia kesakitan.git grep -rl oldtext . | xargs sed -i 's/oldtext/newtext/g'
. itu tidak baik sama sekali untuk mendapatkan.git
dir AndaSemua triknya hampir sama, tapi saya suka yang ini:
find <mydir>
: lihat di direktori.-type f
:-exec command {} +
:sumber
file
perintah untuk mencoba menentukan jenis file masing-masing, tetapi variasi serampangan dalam outputnya mungkin sedikit membingungkan. Opsi-I
(alias--mime
) agak membantu, atau--mime-type
jika Anda memilikinya. Bagaimana tepatnya untuk memperbaiki ini satu-liner rapi untuk melakukan ini sayangnya di luar jangkauan untuk kotak komentar kecil ini. Mungkin memposting pertanyaan terpisah jika Anda butuh bantuan? (Mungkin tambahkan komentar dengan tautan di sini.)sumber
-print0
danxargs
bukannya-exec
atau-execdir
?find -exec command {} +
- itu memang menghindari pemanggilan perintah yang berlebihan seperti xargs, tetapi tanpa proses terpisah.find -exec ... {} +
telah ditentukan POSIX sejak 2006.Bagi saya solusi termudah untuk diingat adalah https://stackoverflow.com/a/2113224/565525 , yaitu:
CATATAN :
-i ''
memecahkan masalah OSXsed: 1: "...": invalid command code .
CATATAN : Jika ada terlalu banyak file untuk diproses, Anda akan mendapatkannya
Argument list too long
. Solusi - penggunaanfind -exec
atauxargs
solusi yang dijelaskan di atas.sumber
workaround
harus sintaks yang lebih disukai dalam semua kasus.$(find...)
adalah bahwa tidak ada cara bagi shell untuk menangani nama file dengan spasi putih atau karakter meta shell lainnya di dalamnya. Jika Anda tahu ini bukan masalah, pendekatan ini baik-baik saja; tetapi kami memiliki terlalu banyak pertanyaan di mana orang tidak diberi peringatan tentang masalah ini, atau tidak memahami peringatan itu.Bagi siapa pun yang menggunakan pencari perak (
ag
)Karena ag mengabaikan file / folder git / hg / svn secara default, ini aman untuk dijalankan di dalam repositori.
sumber
Satu oneliner yang bagus sebagai tambahan. Menggunakan git grep.
sumber
refactor() { echo "Replacing $1 by $2 in all files in this git repository." git grep -lz $1| xargs -0 perl -i'' -pE "s/$1/$2/g" }
Usage, misalnya untuk mengganti 'kata' dengan 'pedang':refactor word sword
lalu verifikasi dengan apa itugit diff
.Untuk mengurangi file secara rekursif
sed
, Anda bisagrep
menggunakan string misalnya:Jika Anda menjalankan,
man grep
Anda akan melihat bahwa Anda juga dapat menentukan--exlude-dir="*.git"
bendera jika Anda ingin menghilangkan pencarian melalui direktori .git, menghindari masalah indeks git seperti yang orang lain tunjukkan dengan sopan.Menuntun Anda ke:
sumber
Yang ini kompatibel dengan repositori git, dan sedikit lebih sederhana:
Linux:
Mac:
(Terima kasih kepada http://blog.jasonmeridth.com/posts/use-git-grep-to-replace-strings-in-files-in-your-git-repository/ )
sumber
git-grep
's-z
pilihan bersama denganxargs -0
.git grep
jelas hanya masuk akal dalamgit
repo. Pengganti umum akan menjadigrep -r
.-z
,git-grep
akan memisahkan bidang output dengan null byte, bukan baris baru; dan dengan-0
,xargs
akan membaca input yang dipisahkan oleh byte nol, bukannya kosong (dan tidak melakukan hal-hal aneh dengan tanda kutip). Jadi jika Anda tidak ingin perintah untuk istirahat jika nama file mengandung spasi, tanda kutip atau karakter lucu lainnya, perintahnya adalah:git grep -z -l 'original_text' | xargs -0 sed ...
.find /home/www/ -type f
akan mencantumkan semua file di / home / www / (dan subdirektori-nya). Bendera "-exec" memberi tahu find untuk menjalankan perintah berikut pada setiap file yang ditemukan.adalah perintah yang dijalankan pada file (banyak sekaligus). The
{}
akan digantikan oleh nama file. Di+
akhir perintah memberitahufind
untuk membangun satu perintah untuk banyak nama file.Per
find
halaman manual: "Baris perintah dibangun dengan cara yang sama seperti xargs membangun baris perintahnya."Dengan demikian dimungkinkan untuk mencapai tujuan Anda (dan menangani nama file yang mengandung spasi) tanpa menggunakan
xargs -0
, atau-print0
.sumber
Saya hanya membutuhkan ini dan tidak senang dengan kecepatan contoh yang tersedia. Jadi saya membuat sendiri:
Ack-grep sangat efisien dalam menemukan file yang relevan. Perintah ini menggantikan ~ 145.000 file dengan mudah, sedangkan yang lain memakan waktu sangat lama sehingga saya tidak bisa menunggu sampai selesai.
sumber
grep -ril 'subdomainA' *
tidak ada yang dekat secepatgrep -Hr 'subdomainA' * | cut -d: -f1
.Metode langsung jika Anda perlu mengecualikan direktori (
--exclude-dir=.svn
) dan juga mungkin memiliki nama file dengan spasi (menggunakan 0Byte dengangrep -Z
danxargs -0
sumber
Cara termudah untuk mengganti ( semua file, direktori, rekursif )
Catatan: Terkadang Anda mungkin perlu mengabaikan beberapa file tersembunyi yaitu
.git
, Anda dapat menggunakan perintah di atas.Jika Anda ingin menyertakan file tersembunyi gunakan,
Dalam kedua kasus string
foo
akan diganti dengan string barubar
sumber
grep -lr 'subdomainA.example.com' | while read file; do sed -i "s/subdomainA.example.com/subdomainB.example.com/g" "$file"; done
Saya kira sebagian besar orang tidak tahu bahwa mereka dapat menyalurkan sesuatu ke dalam file "sambil membaca" dan itu menghindari argumen -print0 jahat, sementara ruang presevering dalam nama file.
Lebih lanjut menambahkan
echo
sebelum sed memungkinkan Anda untuk melihat file apa yang akan berubah sebelum benar-benar melakukannya.sumber
-print0
berguna adalah bahwa ia menangani kasus-kasus yangwhile read
tidak bisa ditangani - baris baru adalah karakter yang valid dalam nama file Unix, jadi agar kode Anda benar-benar kuat, perlu juga menangani nama file seperti itu. (Juga, Anda inginread -r
menghindari beberapa perilaku warisan POSIX yang sial diread
.)sed
ini adalah no-op jika tidak ada kecocokan, jadigrep
itu tidak benar-benar diperlukan; meskipun ini adalah pengoptimalan yang berguna untuk menghindari menulis ulang file yang tidak mengandung kecocokan, jika Anda memiliki banyak, atau ingin menghindari memperbarui cap tanggal pada file yang tidak perlu.Anda dapat menggunakan awk untuk menyelesaikan ini seperti di bawah ini,
harap ini akan membantu Anda !!!
sumber
sed
perintah berbasis gagal ketika binari dimasukkan bahkan dengan pengaturan spesifik osx.find
kembali memiliki ruang dalam nama mereka! Ini jauh lebih aman untuk digunakanwhile read
: stackoverflow.com/a/9612560/1938956Coba ini:
sumber
sed -i 's/subdomainA/subdomainB/g'
`grep -ril 'subdomainA' /home/www/*
` - ini masih tidak terlihat terlalu bagus, tetapi seharusnya selamat dari copypaste :) Cheers!sumber
Menurut posting blog ini :
sumber
/
? Misalnya, saya ingin mengganti alamat IP:xxx.xxx.xxx.xxx
untukxxx.xxx.xxx.xxx/folder
/
dengan \. Misalnya:find . -type f | xargs perl -pi -e 's/xxx.xxx.xxx.xxx\/folder/newtext/g;'
Jika Anda tidak keberatan menggunakan
vim
bersama-sama dengangrep
ataufind
alat, Anda bisa menindaklanjuti jawaban yang diberikan oleh pengguna Gert di tautan ini -> Bagaimana cara melakukan penggantian teks dalam hierarki folder besar? .Inilah kesepakatannya:
grep secara rekursif untuk string yang ingin Anda ganti di jalur tertentu, dan ambil hanya path lengkap dari file yang cocok. (itu akan menjadi
$(grep 'string' 'pathname' -Rl)
.(opsional) jika Anda ingin melakukan pra-backup file-file itu pada direktori terpusat mungkin Anda dapat menggunakan ini juga:
cp -iv $(grep 'string' 'pathname' -Rl) 'centralized-directory-pathname'
setelah itu Anda dapat mengedit / mengganti sesuka hati dalam
vim
mengikuti skema yang mirip dengan yang disediakan pada tautan yang diberikan::bufdo %s#string#replacement#gc | update
sumber
Sekolah yang agak tua tetapi ini bekerja pada OS X.
Ada beberapa trik:
• Hanya akan mengedit file dengan ekstensi di
.sls
bawah direktori saat ini•
.
harus melarikan diri untuk memastikansed
tidak mengevaluasi mereka sebagai "karakter apa pun"•
,
digunakan sebagaised
pembatas sebagai ganti dari yang biasa/
Juga perhatikan ini untuk mengedit template Jinja untuk melewati
variable
di jalurimport
(tapi ini di luar topik).Pertama, verifikasi perintah sed Anda melakukan apa yang Anda inginkan (ini hanya akan mencetak perubahan ke stdout, itu tidak akan mengubah file):
Edit perintah sed sesuai kebutuhan, setelah Anda siap untuk melakukan perubahan:
Catat
-i ''
dalam perintah sed , saya tidak ingin membuat cadangan dari file asli (seperti yang dijelaskan dalam In-place edit dengan sed pada OS X atau dalam komentar Robert Lujo di halaman ini).Selamat seding orang!
sumber
hanya untuk menghindari berubah juga
tetapi tetap saja
(mungkin tidak baik dalam ide di balik root domain)
sumber
Saya hanya menggunakan atasan:
sumber
Inilah versi yang harus lebih umum daripada kebanyakan; itu tidak memerlukan
find
(menggunakandu
gantinya), misalnya. Memang diperlukanxargs
, yang hanya ditemukan di beberapa versi Plan 9 (seperti 9front)Jika Anda ingin menambahkan filter seperti ekstensi file gunakan
grep
:sumber
Untuk Qshell (qsh) di IBMi, bukan bash seperti yang ditandai oleh OP.
Keterbatasan perintah qsh:
Demikian solusi dalam qsh:
Peringatan:
sumber
for
.Jika Anda ingin menggunakan ini tanpa sepenuhnya menghancurkan repositori SVN Anda, Anda dapat memberi tahu 'find' untuk mengabaikan semua file tersembunyi dengan melakukan:
sumber
Menggunakan kombinasi
grep
dansed
sumber
grep -Rl pattern
dihasilkan daftar file di mana polanya. File tidak dibaca dalamfor
lingkaran.for
lingkaran; jika ada nama file yang dikembalikan berisi spasi, itu tidak akan berfungsi dengan benar, karena shell tokenizesfor
daftar argumen. Tapi kemudian Anda menggunakan variabel nama file tanpa tanda kutip di dalam loop, jadi itu akan pecah di sana jika Anda memperbaikinya. Mengoreksi bug yang tersisa ini akan membuat Anda identik dengan jawaban @ MadMan2064.Untuk mengganti semua kejadian di repositori git, Anda dapat menggunakan:
Lihat Daftar file dalam repo git lokal? untuk opsi lain untuk membuat daftar semua file dalam repositori. The
-z
pilihan memberitahu git untuk memisahkan nama file dengan byte nol, yang menjamin bahwaxargs
(dengan pilihan-0
) dapat memisahkan nama file, bahkan jika mereka berisi spasi atau entah apa lagi.sumber
sumber
awk
/sed
, tetapi perl adalah umum (kecuali embedded / sistem dengan busybox saja).untuk mengubah banyak file (dan menyimpan cadangan sebagai
*.bak
):akan mengambil semua file dalam direktori dan ganti
|
dengan x yang disebut "Perl pie" (semudah pie)sumber