Bagaimana cara melakukan substitusi di tempat yang hanya membuat cadangan file yang diubah?

13

Saya menjalankan yang berikut ini untuk mengganti istilah yang digunakan dalam semua file di direktori kerja saat ini:

$ find . -type f -print0 | xargs -0 sed -i'.bup' -e's/Ms. Johnson/Mrs. Melbin/g'

Ini melakukan substitusi kata tetapi juga membuat .bupfile file yang tidak pernah memiliki Ms. Johnsonstring.

Bagaimana saya melakukan penggantian tanpa membuat semua cadangan yang tidak perlu ini?

Belmin Fernandez
sumber
Sepertinya saya sebagai bug sed see
Hotschke
Mungkin ada pendekatan yang lebih baik menggunakan ex, dan kondisional (hanya jika file diubah) berjalan :!cp '%' '%.bup'sebelum menyimpan dan keluar. Mungkin layak untuk dilihat.
Wildcard
Saya menulis pertanyaan tentang ide saya di atas pada vipertukaran stack.
Wildcard

Jawaban:

6

Anda dapat memeriksa konten file untuk memastikan bahwa akan terjadi substitusi ketika sedberoperasi di dalamnya:

find . \
    -type f \
    -exec grep -q 'Ms. Johnson' {} \; \
    -print0 |
xargs -0 sed -i'.bup' -e's/Ms. Johnson/Mrs. Melbin/g'

Jika Anda ingin benar-benar pandai tentang hal itu, Anda bisa melepaskannya findsama sekali:

grep -Z -l -r 'Ms. Johnson' |
    xargs -0 sed -i'.bup' -e's/Ms. Johnson/Mrs. Melbin/g'
amphetamachine
sumber
1
Saya pikir Anda perlu '{}'sebelum Anda \;dalam hal itu -exec.
Jander
8

Find memiliki -execoperator yang mengeksekusi perintah arbitrer. Yang lebih baik lagi -execadalah tes , jadi Anda dapat membuat beberapa rantai menjadi -execsatu, dan jika perintah sebelumnya gagal, yang kemudian tidak akan dieksekusi. String {}akan diganti dengan nama file saat ini, dan ;menandai akhir perintah. Anda harus mengutip keduanya untuk menghindari campur tangan shell.

Begitu:

find . -type f \
    -exec grep -q 'Ms. Johnson' '{}' \; \
    -exec sed -i'.bup' -e's/Ms. Johnson/Mrs. Melbin/g' '{}' \;
Jander
sumber
Saya tidak pernah mengalami masalah menggunakan bare {}.
amphetamachine
1
@amphetamachine: Aku juga tidak, tetapi halaman manual menyarankan itu. Ini bisa berupa hal csh, atau mungkin ada shell (bukan Bash dan tidak POSIX) yang berkembang {}ke string nol saat melakukan ekspansi penjepit.
Jander
4

Saya melihat halaman manual dan tidak melihat cara untuk melakukannya secara langsung sed, seperti yang saya yakin Anda lakukan sebelum bertanya. Saya melihat beberapa cara untuk mengatasi ini menggunakan grep, tapi saya pikir yang paling mudah adalah ini:

grep -rlZ "Ms. Johnson" . | xargs -0 sed -i'.bup' -e's/Ms. Johnson/Mrs. Melbin/g'

-rrecurse
-lnama file cetak hanya
-Zberakhir nama dengan nol

Kevin
sumber
-1

Sepertinya Anda perlu membuat daftar file yang cocok dengan istilah pencarian Anda terlebih dahulu.

search="test"
for match in $(find -type f -exec grep -l $search "{}" \;)
do sed -i'.bup' -e "/$search/ s/$search/Mrs. Melbin/g" "$match"
done
laebshade
sumber
Anda lupa .argumen pertama find. Juga, seperti yang saya informasikan pada diri saya sendiri belum lama ini, Anda sebenarnya tidak perlu mengutip atau melarikan diri{}
Kevin
Jangan membuat daftar file dan melakukan substitusi perintah untuk itu. Pertama findmenghasilkan daftar file yang dipisahkan baris baru, kemudian shell memecah daftar ini di spasi putih (bukan hanya baris baru) dan kemudian shell memperlakukan setiap kata sebagai pola gumpalan. Ini hanya berfungsi jika nama file Anda tidak mengandung spasi atau \[?*. Jawaban lain pada halaman ini menunjukkan bagaimana melakukan ini dengan benar.
Gilles 'SANGAT berhenti menjadi jahat'
@Kevin Tidak .perlu dengan find (setidaknya find ditemukan di linux) karena diasumsikan ketika tidak ada path yang melewati argumen.
laebshade