Apakah sed meminta konfirmasi sebelum setiap penggantian?


37

Apakah ada cara untuk membuat saya meminta konfirmasi sebelum setiap penggantian? Sesuatu yang mirip dengan 'c' saat menggunakan ganti inside vim.

Apakah sed melakukan ini sama sekali?


3
Secara teknis hal itu mungkin tetapi lebih merupakan latihan intelektual daripada upaya yang bermanfaat. Lihat Bagaimana melakukan penggantian teks dalam hierarki folder besar? yang memiliki solusi Vim dan Perl.
Gilles 'SO- stop being evil'

Saya sedang menggunakan vim (args dan argdo) setiap kali saya perlu 'konfirmasi', tetapi bertanya-tanya apakah ada 'sederhana' cara
Yuvi

1
Ini bertentangan dengan tujuan dasar sed - untuk mengotomatisasi pengeditan melalui aliran.
teppic

@teppic tidak terlalu karena Anda masih harus pergi mencari contoh dalam file teks, yang sed dapat dilakukan untuk Anda. Saya pikir pertanyaannya masuk akal, kalau-kalau Anda menambahkan file yang salah ke daftar dan ingin melihat file apa yang sedang Anda edit
Kolob Canyon

Jawaban:


37

Melakukannya dengan sedmungkin tidak akan mungkin karena itu adalah editor aliran non-interaktif. Membungkus sednaskah akan membutuhkan pemikiran terlalu banyak. Lebih mudah melakukannya dengan vim:

vim -c '%s/PATTERN/REPLACEMENT/gc' -c 'wq' file.in

Karena disebutkan dalam komentar di bawah, inilah cara ini akan digunakan pada banyak file yang cocok dengan pola globbing nama file tertentu di direktori saat ini:

for fname in file*.txt; do
    vim -c '%s/PATTERN/REPLACEMENT/gc' -c 'wq' "$fname"
done

Atau, jika Anda pertama kali ingin memastikan bahwa file tersebut benar-benar berisi garis yang cocok dengan pola yang diberikan terlebih dahulu, sebelum melakukan penggantian,

for fname in file*.txt; do
    grep -q 'PATTERN' "$fname" &&
    vim -c '%s/PATTERN/REPLACEMENT/gc' -c 'wq' "$fname"
done

Dua loop shell di atas diubah menjadi findperintah yang melakukan hal yang sama tetapi untuk semua file dengan nama tertentu di suatu tempat di dalam atau di bawah beberapa top-dirdirektori,

find top-dir -type f -name 'file*.txt' \
    -exec vim -c '%s/PATTERN/REPLACEMENT/gc' -c 'wq' {} \;
find top-dir -type f -name 'file*.txt' \
    -exec grep -q 'PATTERN' {} \; \
    -exec vim -c '%s/PATTERN/REPLACEMENT/gc' -c 'wq' {} \;

Atau, menggunakan loop shell asli dan findmemasukkan nama path ke dalamnya:

find top-dir -type f -name 'file*.txt' -exec sh -c '
    for pathname do
        vim -c "%s/PATTERN/REPLACEMENT/gc" -c "wq" "$pathname"
    done' sh {} +
find top-dir -type f -name 'file*.txt' -exec sh -c '
    for pathname do
        grep -q "PATTERN" "$pathname" &&
        vim -c "%s/PATTERN/REPLACEMENT/gc" -c "wq" "$pathname"
    done' sh {} +

Bagaimanapun, Anda tidak ingin melakukan sesuatu seperti for filename in $( grep -rl ... )itu

  1. itu akan membutuhkan grepselesai berjalan bahkan sebelum memulai iterasi pertama dari loop, yang tidak elegan , dan
  2. nama path yang dikembalikan oleh grepakan dibagi menjadi kata-kata di spasi putih, dan kata-kata ini akan mengalami globbing nama file (ini mendiskualifikasi nama path yang berisi spasi dan karakter khusus).

Terkait:


2
Keuntungannya sedadalah dapat beroperasi pada banyak file, misalnya, sed -i 's/old/new/g' /path/to/*.txtatau sesuatu yang serupa.
user1717828

10
for i in $(grep -rl "old"); do vim -c "%s/old/new/gc" -c "wq" "$i"; done
tcpaiva

@tecepe, harap ubah menjadi jawaban, Terima kasih.
Nishant

1
@Nishant Ini akan menjadi jawaban yang rapuh karena akan mendiskualifikasi file yang berisi spasi putih dalam nama atau pathnya.
Kusalananda

7

Anda bisa mendapatkan ini dengan melakukan seperti:

:%s/OLD_TEXT/NEW_TEXT/gc

Secara khusus, menambahkan cpembatas setelah ketiga.

Perhatikan bahwa opsi 'c' hanya berfungsi di Vim; Anda tidak akan dapat menggunakannya dengan seddi baris perintah.


4
Untuk memperjelas: ini hanya berfungsi di Vim, bukan baris perintah biasa sed.
Brendan

OP ditandai vim, sehingga jawaban ini berlaku; meskipun, jelas vim dan sed memiliki kemampuan yang berbeda
ILMostro_7


-1
searchandreplace () {
if [ -z $2 ] ; then
    realpath * | xargs grep -ins --directories=skip --color=always "$1" | nl -s "."
else
    realpath * | xargs grep -ins --directories=skip --color=always "$1" | nl -s "."
    exp=$(realpath * | xargs grep -ins --directories=skip --color=never "$1" | cut -d':' -f1,2 | awk -F':' '{print $2 $1}' | sed -E "s|^[0-9]+|sed -i \'&s/|; s|//|/"$1"/"$2"/g\' /|")
    IFS=$'\n'
    for d in $exp
        do
        read -p "Exec $(echo -e -n "\033[1;31m$d\033[0m")? " -e REP
            if [ "$REP" = y ]; then
            echo `bash -c $d`;
            fi
    done
fi
}

Jika Anda memberi makan ini dengan argumen tunggal - searchandreplace "AAA"- itu hanya mencari string itu di direktori saat ini, tetapi jika Anda memberi makan dengan argumen ganda - searchandreplace AAA BBB- maka di samping itu juga meminta Anda untuk mengganti yang pertama dengan yang kedua "baris oleh baris "untuk setiap baris.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.