Bagaimana cara mencari / mengganti string dengan awk atau sed secara rekursif?

678

Bagaimana cara menemukan dan mengganti setiap kemunculan:

subdomainA.example.com

dengan

subdomainB.example.com

di setiap file teks di bawah /home/www/pohon direktori secara rekursif?

Tedd
sumber
93
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.

Untuk informasi lebih lanjut, lihat man find.

Reedwolf
sumber
132
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.

John Zwinck
sumber
50
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'
Anatoly
sumber
1
@Anatoly: hanya satu pertanyaan: bagaimana saya bisa mengecualikan file biner (file executable) ?
user2284570
3
@ user2284570 Gunakan -Iatau --binary-file=without-matchgrep flag.
Zéychin
34
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.

I159
sumber
@ 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'
Mempekerjakan bahasa Rusia
sumber
2
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.
Charles Duffy
34

Bagi saya solusi termudah untuk diingat adalah https://stackoverflow.com/a/2113224/565525 , yaitu:

sed -i '' -e 's/subdomainA/subdomainB/g' $(find /home/www/ -type f)

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 - penggunaan find -execatau xargssolusi yang dijelaskan di atas.

Robert Lujo
sumber
4
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.
tripleee
30

Bagi siapa pun yang menggunakan pencari perak ( ag)

ag SearchString -l0 | xargs -0 sed -i 's/SearchString/Replacement/g'

Karena ag mengabaikan file / folder git / hg / svn secara default, ini aman untuk dijalankan di dalam repositori.

Jacob Wang
sumber
16

Satu oneliner yang bagus sebagai tambahan. Menggunakan git grep.

git grep -lz 'subdomainA.example.com' | xargs -0 perl -i'' -pE "s/subdomainA.example.com/subdomainB.example.com/g"
Jimmy Kane
sumber
3
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
domdambrogia
sumber
13

Yang ini kompatibel dengan repositori git, dan sedikit lebih sederhana:

Linux:

git grep -l 'original_text' | xargs sed -i 's/original_text/new_text/g'

Mac:

git grep -l 'original_text' | xargs sed -i '' -e 's/original_text/new_text/g'

(Terima kasih kepada http://blog.jasonmeridth.com/posts/use-git-grep-to-replace-strings-in-files-in-your-git-repository/ )

seddonym
sumber
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.

perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g' {} +

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.

unutbu
sumber
8

Saya hanya membutuhkan ini dan tidak senang dengan kecepatan contoh yang tersedia. Jadi saya membuat sendiri:

cd /var/www && ack-grep -l --print0 subdomainA.example.com | xargs -0 perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g'

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.

Henno
sumber
Bagus, tetapi grep -ril 'subdomainA' *tidak ada yang dekat secepat grep -Hr 'subdomainA' * | cut -d: -f1.
trusktr
@ Halo: hanya satu pertanyaan: bagaimana saya bisa mengecualikan file biner (file yang dapat dieksekusi) ?
user2284570
ack-grep melakukan itu secara otomatis untuk Anda.
Henno
@ Henno: Apakah ini termasuk skrip shell?
user2284570
Iya. Berikut adalah daftar lengkap jenis file mendukung: beyondgrep.com/documentation
Henno
6

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'
inetphantom
sumber
6

Cara termudah untuk mengganti ( semua file, direktori, rekursif )

find . -type f -not -path '*/\.*' -exec sed -i 's/foo/bar/g' {} +

Catatan: Terkadang Anda mungkin perlu mengabaikan beberapa file tersembunyi yaitu .git, Anda dapat menggunakan perintah di atas.

Jika Anda ingin menyertakan file tersembunyi gunakan,

find . -type f  -exec sed -i 's/foo/bar/g' {} +

Dalam kedua kasus string fooakan diganti dengan string barubar

Sazzad Hissain Khan
sumber
5

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.

MadMan2064
sumber
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,

for file in `find /home/www -type f`
do
   awk '{gsub(/subdomainA.example.com/,"subdomainB.example.com"); print $0;}' $file > ./tempFile && mv ./tempFile $file;
done

harap ini akan membantu Anda !!!

sarath kumar
sumber
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' *`
RikHic
sumber
1
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}"
    fi

done
petrus4
sumber
4

Menurut posting blog ini :

find . -type f | xargs perl -pi -e 's/oldtext/newtext/g;'
J.Hpour
sumber
Bagaimana Anda bisa lolos dari tebasan /? Misalnya, saya ingin mengganti alamat IP: xxx.xxx.xxx.xxxuntukxxx.xxx.xxx.xxx/folder
Pathros
Anda dapat melarikan diri /dengan \. Misalnya:find . -type f | xargs perl -pi -e 's/xxx.xxx.xxx.xxx\/folder/newtext/g;'
J.Hpour
3

Jika Anda tidak keberatan menggunakan vimbersama-sama dengan grepatau findalat, 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 vimmengikuti skema yang mirip dengan yang disediakan pada tautan yang diberikan:

    • :bufdo %s#string#replacement#gc | update
mzcl-mn
sumber
2

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).

Selamat seding orang!

Raphvanns
sumber
2

hanya untuk menghindari berubah juga

  • NearlysubdomainA.example.com
  • subdomainA.example.comp.other

tetapi tetap saja

  • subdomainA.example.com.IsIt.good

(mungkin tidak baik dalam ide di balik root domain)

find /home/www/ -type f -exec sed -i 's/\bsubdomainA\.example\.com\b/\1subdomainB.example.com\2/g' {} \;
NeronLeVelu
sumber
2

Saya hanya menggunakan atasan:

find . -name '*.[c|cc|cp|cpp|m|mm|h]' -print0 |  xargs -0 tops -verbose  replace "verify_noerr(<b args>)" with "__Verify_noErr(<args>)" \
replace "check(<b args>)" with "__Check(<args>)" 
tgunr
sumber
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'
bbarker
sumber
1

Untuk Qshell (qsh) di IBMi, bukan bash seperti yang ditandai oleh OP.

Keterbatasan perintah qsh:

  • find tidak memiliki opsi -print0
  • xargs tidak memiliki opsi -0
  • sed tidak memiliki opsi -i

Demikian solusi dalam qsh:

    PATH='your/path/here'
    SEARCH=\'subdomainA.example.com\'
    REPLACE=\'subdomainB.example.com\'

    for file in $( find ${PATH} -P -type f ); do

            TEMP_FILE=${file}.${RANDOM}.temp_file

            if [ ! -e ${TEMP_FILE} ]; then
                    touch -C 819 ${TEMP_FILE}

                    sed -e 's/'$SEARCH'/'$REPLACE'/g' \
                    < ${file} > ${TEMP_FILE}

                    mv ${TEMP_FILE} ${file}
            fi
    done

Peringatan:

  • Solusi tidak termasuk penanganan kesalahan
  • Bukan Bash yang ditandai oleh OP
Christoff Erasmus
sumber
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'
Marcus Floyd
sumber
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
Pawel
sumber
@ 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.

Perseids
sumber
1
perl -p -i -e 's/oldthing/new_thingy/g' `grep -ril oldthing *`
Sheena
sumber
1
Tidak menggunakan awk/ sed, tetapi perl adalah umum (kecuali embedded / sistem dengan busybox saja).
pevik
1

untuk mengubah banyak file (dan menyimpan cadangan sebagai *.bak):

perl -p -i -e "s/\|/x/g" *

akan mengambil semua file dalam direktori dan ganti |dengan x yang disebut "Perl pie" (semudah pie)

Stenemo
sumber
Tidak rekursif melalui direktori.
PKHunter
adalah mungkin untuk menyalurkannya, yang membuatnya sangat dapat disesuaikan, termasuk melalui direktori. josephscott.org/archives/2005/08/… dan unix.stackexchange.com/questions/101415/…
Stenemo