GNU/Linux >> Belajar Linux >  >> Linux

Bagaimana Cara Mengganti String Dalam File?

Mengganti string dalam file berdasarkan kriteria pencarian tertentu adalah tugas yang sangat umum. Bagaimana saya bisa

  • ganti string foo dengan bar di semua file di direktori saat ini?
  • lakukan hal yang sama secara rekursif untuk sub direktori?
  • ganti hanya jika nama file cocok dengan string lain?
  • ganti hanya jika string ditemukan dalam konteks tertentu?
  • ganti jika string berada pada nomor baris tertentu?
  • ganti beberapa string dengan pengganti yang sama
  • ganti beberapa string dengan pengganti yang berbeda

Jawaban yang Diterima:

1. Mengganti semua kemunculan satu string dengan yang lain di semua file di direktori saat ini:

Ini untuk kasus di mana Anda tahu bahwa direktori hanya berisi file biasa dan Anda ingin memproses semua file yang tidak disembunyikan. Jika bukan itu masalahnya, gunakan pendekatan di 2.

Semua sed solusi dalam jawaban ini menganggap GNU sed . Jika menggunakan FreeBSD atau macOS, ganti -i dengan -i '' . Perhatikan juga bahwa penggunaan -i beralih dengan versi sed memiliki implikasi keamanan sistem file tertentu dan tidak disarankan dalam skrip apa pun yang Anda rencanakan untuk didistribusikan dengan cara apa pun.

  • Non rekursif, file dalam direktori ini saja:

     sed -i -- 's/foo/bar/g' *
     perl -i -pe 's/foo/bar/g' ./* 
    

(perl satu akan gagal untuk nama file yang diakhiri dengan | atau spasi)).

  • File reguler dan rekursif (termasuk yang tersembunyi ) di ini dan semua subdirektori

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

    Jika Anda menggunakan zsh:

     sed -i -- 's/foo/bar/g' **/*(D.)
    

    (mungkin gagal jika daftar terlalu besar, lihat zargs untuk bekerja di sekitar).

    Bash tidak dapat memeriksa file biasa secara langsung, diperlukan loop (kawat gigi menghindari pengaturan opsi secara global):

     ( shopt -s globstar dotglob;
         for file in **; do
             if [[ -f $file ]] && [[ -w $file ]]; then
                 sed -i -- 's/foo/bar/g' "$file"
             fi
         done
     )
    

    File-file tersebut dipilih ketika mereka adalah file yang sebenarnya (-f) dan mereka dapat ditulis (-w).

2. Ganti hanya jika nama file cocok dengan string lain / memiliki ekstensi tertentu / dari jenis tertentu dll:

  • Non-rekursif, file dalam direktori ini saja:

    sed -i -- 's/foo/bar/g' *baz*    ## all files whose name contains baz
    sed -i -- 's/foo/bar/g' *.baz    ## files ending in .baz
    
  • File reguler dan rekursif di subdirektori ini dan semua

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

    Jika Anda menggunakan bash (kawat gigi menghindari pengaturan opsi secara global):

    ( shopt -s globstar dotglob
        sed -i -- 's/foo/bar/g' **baz*
        sed -i -- 's/foo/bar/g' **.baz
    )
    

    Jika Anda menggunakan zsh:

    sed -i -- 's/foo/bar/g' **/*baz*(D.)
    sed -i -- 's/foo/bar/g' **/*.baz(D.)
    

-- berfungsi untuk memberitahu sed bahwa tidak ada lagi flag yang akan diberikan di baris perintah. Ini berguna untuk melindungi dari nama file yang dimulai dengan - .

  • Jika file bertipe tertentu, misalnya, dapat dieksekusi (lihat man find untuk opsi lainnya):

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

zsh :

    sed -i -- 's/foo/bar/g' **/*(D*)

3. Ganti hanya jika string ditemukan dalam konteks tertentu

  • Ganti foo dengan bar hanya jika ada baz nanti di baris yang sama:

     sed -i 's/foo(.*baz)/bar1/' file
    

Di sed , menggunakan ( ) menyimpan apa pun yang ada di dalam tanda kurung dan Anda kemudian dapat mengaksesnya dengan 1 . Ada banyak variasi dari tema ini, untuk mempelajari lebih lanjut tentang ekspresi reguler tersebut, lihat di sini.

  • Ganti foo dengan bar hanya jika foo ditemukan pada kolom 3d (bidang) dari file input (dengan asumsi bidang yang dipisahkan spasi):

     gawk -i inplace '{gsub(/foo/,"baz",$3); print}' file
    

(perlu gawk 4.1.0 atau lebih baru).

  • Untuk bidang yang berbeda cukup gunakan $N dimana N adalah jumlah bidang yang diminati. Untuk pemisah bidang yang berbeda (: dalam contoh ini) gunakan:

     gawk -i inplace -F':' '{gsub(/foo/,"baz",$3);print}' file
    

Solusi lain menggunakan perl :

    perl -i -ane '$F[2]=~s/foo/baz/g; $" = " "; print "@Fn"' foo 

CATATAN:keduanya awk dan perl solusi akan mempengaruhi spasi dalam file (hapus awal dan akhir kosong, dan ubah urutan kosong menjadi satu karakter spasi di baris yang cocok). Untuk bidang yang berbeda, gunakan $F[N-1] dimana N adalah nomor bidang yang Anda inginkan dan untuk penggunaan pemisah bidang yang berbeda ($"=":" menyetel pemisah bidang keluaran ke : ):

    perl -i -F':' -ane '$F[2]=~s/foo/baz/g; $"=":";print "@F"' foo 
  • Ganti foo dengan bar hanya di baris ke-4:

     sed -i '4s/foo/bar/g' file
     gawk -i inplace 'NR==4{gsub(/foo/,"baz")};1' file
     perl -i -pe 's/foo/bar/g if $.==4' file
    

4. Beberapa operasi penggantian:ganti dengan string yang berbeda

  • Anda dapat menggabungkan sed perintah:

     sed -i 's/foo/bar/g; s/baz/zab/g; s/Alice/Joan/g' file
    

Ketahuilah bahwa pesanan itu penting (sed 's/foo/bar/g; s/bar/baz/g' akan menggantikan foo dengan baz ).

  • atau perintah Perl

     perl -i -pe 's/foo/bar/g; s/baz/zab/g; s/Alice/Joan/g' file
    
  • Jika Anda memiliki banyak pola, akan lebih mudah untuk menyimpan pola Anda dan penggantinya dalam sed file skrip:

     #! /usr/bin/sed -f
     s/foo/bar/g
     s/baz/zab/g
    
  • Atau, jika Anda memiliki terlalu banyak pasangan pola agar hal di atas dapat dilakukan, Anda dapat membaca pasangan pola dari sebuah file (dua pola yang dipisahkan spasi, $pattern dan $replacement, per baris):

     while read -r pattern replacement; do   
         sed -i "s/$pattern/$replacement/" file
     done < patterns.txt
    
  • Itu akan sangat lambat untuk daftar panjang pola dan file data besar sehingga Anda mungkin ingin membaca pola dan membuat sed skrip dari mereka sebagai gantinya. Berikut ini mengasumsikan <spasi> pembatas memisahkan daftar MATCH<spasi>REPLACE pasangan terjadi satu per baris dalam file patterns.txt :

     sed 's| *([^ ]*) *([^ ]*).*|s/1/2/g|' <patterns.txt |
     sed -f- ./editfile >outfile
    

Format di atas sebagian besar bersifat arbitrer dan, misalnya, tidak mengizinkan <spasi> di salah satu dari MATCH atau GANTI . Metode ini sangat umum:pada dasarnya, jika Anda dapat membuat aliran keluaran yang terlihat seperti sed script, maka Anda dapat sumber aliran itu sebagai sed skrip dengan menentukan sed file skrip sebagai - stdin.

  • Anda dapat menggabungkan dan menggabungkan beberapa skrip dengan cara yang sama:

     SOME_PIPELINE |
     sed -e'#some expression script'  
         -f./script_file -f-          
         -e'#more inline expressions' 
     ./actual_edit_file >./outfile
    

Sebuah POSIX sed akan menggabungkan semua skrip menjadi satu dalam urutan yang muncul di baris perintah. Tak satu pun dari kebutuhan ini diakhiri dengan n baris baru.

  • grep dapat bekerja dengan cara yang sama:

     sed -e'#generate a pattern list' <in |
     grep -f- ./grepped_file
    
  • Saat bekerja dengan string tetap sebagai pola, adalah praktik yang baik untuk menghindari ekspresi reguler metacharacters . Anda dapat melakukannya dengan lebih mudah:

     sed 's/[]$&^*./[]/\&/g
          s| *([^ ]*) *([^ ]*).*|s/1/2/g|
     ' <patterns.txt |
     sed -f- ./editfile >outfile
    

5. Operasi penggantian ganda:ganti beberapa pola dengan string yang sama

  • Ganti salah satu foo , bar atau baz dengan foobar

     sed -Ei 's/foo|bar|baz/foobar/g' file
    
  • atau

     perl -i -pe 's/foo|bar|baz/foobar/g' file
    

Linux
  1. Bagaimana Cara Menggunakan Sed Untuk Mengganti String Multi-baris?

  2. Bagaimana Mengganti String Dengan String Yang Mengandung Slash Dengan Sed?

  3. Hapus kemunculan string dalam file teks

  1. Bagaimana cara menyisipkan teks di awal file?

  2. Cara mengganti string dalam banyak file di baris perintah linux

  3. tr perintah - cara mengganti string \n dengan baris baru yang sebenarnya (\n)

  1. ganti kemunculan string ke-n di setiap baris file teks

  2. sed:bagaimana cara mengganti baris jika ditemukan atau ditambahkan ke akhir file jika tidak ditemukan?

  3. Bagaimana cara mengganti karakter dengan sed secara rekursif?