Bagaimana saya bisa mengganti string dalam file?

751

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

  • ganti string foodengan bardi semua file di direktori saat ini?
  • melakukan 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 ada pada nomor baris tertentu?
  • ganti beberapa string dengan penggantian yang sama
  • ganti beberapa string dengan penggantian yang berbeda
terdon
sumber
2
Ini dimaksudkan sebagai tanya jawab kanonik tentang hal ini (lihat diskusi meta ini ), silakan mengedit jawaban saya di bawah ini atau menambahkan jawaban Anda.
terdon

Jawaban:

1009

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

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

Semua sedsolusi dalam jawaban ini menganggap GNU sed. Jika menggunakan FreeBSD atau OS / X, ganti -idengan -i ''. Perhatikan juga bahwa penggunaan -iswitch dengan versi apa pun sedmemiliki implikasi keamanan sistem file tertentu dan tidak disarankan dalam skrip apa pun yang Anda rencanakan untuk didistribusikan dengan cara apa pun.

  • Non rekursif, hanya file dalam direktori ini:

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

    (yang perlakan gagal untuk nama file yang diakhiri |atau spasi) ).

  • File rekursif dan teratur ( 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 zargsuntuk bekerja di sekitar).

    Bash tidak dapat memeriksa langsung untuk file biasa, 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 dipilih ketika mereka adalah file aktual (-f) dan mereka dapat ditulis (-w).

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

  • Non-rekursif, hanya file dalam direktori ini:

    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 rekursif dan teratur dalam subdirektori ini dan semua

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

    Jika Anda menggunakan bash (kawat gigi hindari 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.)

    The --servis untuk memberitahu sedbahwa tidak ada lagi bendera akan diberikan pada command line. Ini berguna untuk melindungi terhadap nama file yang dimulai dengan -.

  • Jika suatu file berjenis tertentu, misalnya, dapat dieksekusi (lihat man findopsi 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 foodengan barhanya jika ada bazkemudian pada baris yang sama:

    sed -i 's/foo\(.*baz\)/bar\1/' file

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

  • Ganti foodengan barhanya jika fooditemukan pada kolom 3d (lapangan) dari file input (dengan asumsi bidang spasi-terpisah):

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

    (perlu gawk4.1.0 atau lebih baru).

  • Untuk bidang yang berbeda cukup gunakan di $Nmana Njumlah 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 "@F\n"' foo 

    CATATAN: keduanya awkdan perlsolusi akan memengaruhi penspasian dalam file (menghapus blanko terkemuka dan tertinggal, dan mengonversi sekuens blank menjadi satu karakter spasi pada baris yang cocok). Untuk bidang yang berbeda, gunakan di $F[N-1]mana Nnomor bidang yang Anda inginkan dan untuk penggunaan pemisah bidang yang berbeda ( $"=":"set pemisah bidang keluaran untuk :):

    perl -i -F':' -ane '$F[2]=~s/foo/baz/g; $"=":";print "@F"' foo 
  • Ganti foodengan barhanya pada 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 sedperintah:

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

    Sadarilah bahwa pesanan itu penting ( sed 's/foo/bar/g; s/bar/baz/g'akan diganti foodengan baz).

  • atau perintah Perl

    perl -i -pe 's/foo/bar/g; s/baz/zab/g; s/Alice/Joan/g' file
  • Jika Anda memiliki sejumlah besar pola, lebih mudah untuk menyimpan pola dan penggantiannya dalam sedfile skrip:

    #! /usr/bin/sed -f
    s/foo/bar/g
    s/baz/zab/g
  • Atau, jika Anda memiliki terlalu banyak pasangan pola untuk dapat di atas, Anda dapat membaca pasangan pola dari file (dua pola yang dipisahkan spasi, $ pola dan $ penggantian, 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 sedskrip dari mereka. Pembatas berikut mengasumsikan pembatas <spasi> memisahkan daftar MATCH <spasi> REPLACE pasang yang 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 arbitrer dan, misalnya, tidak memungkinkan untuk <spasi> dalam MATCH atau REPLACE . Metode ini sangat umum: pada dasarnya, jika Anda dapat membuat aliran keluaran yang terlihat seperti sedskrip, maka Anda dapat sumber aliran tersebut sebagai sedskrip dengan menetapkan sedfile 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

    POSIX sedakan menggabungkan semua skrip menjadi satu sesuai dengan urutannya pada baris perintah. Tak satu pun dari ini perlu diakhiri dengan \newline.

  • grep dapat bekerja dengan cara yang sama:

    sed -e'#generate a pattern list' <in |
    grep -f- ./grepped_file
  • Ketika bekerja dengan string-tetap sebagai pola, adalah praktik yang baik untuk melepaskan karakter metaforeks reguler . Anda dapat melakukan ini dengan agak mudah:

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

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

  • Ganti salah satu dari foo, baratau bazdenganfoobar

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

    perl -i -pe 's/foo|bar|baz/foobar/g' file
terdon
sumber
2
@ StéphaneChazelas terima kasih untuk hasil editnya, ia memang memperbaiki beberapa hal. Namun, harap jangan hapus informasi yang relevan dengan bash. Tidak semua orang menggunakan zsh. Dengan segala cara menambahkan zshinfo tetapi tidak ada alasan untuk menghapus hal-hal bash. Juga, saya tahu bahwa menggunakan shell untuk pemrosesan teks tidak ideal tetapi ada beberapa kasus di mana dibutuhkan. Saya mengedit dalam versi yang lebih baik dari skrip asli saya yang akan membuat sedskrip daripada benar-benar menggunakan shell loop untuk menguraikan. Ini dapat bermanfaat jika Anda memiliki beberapa ratus pasang pola misalnya.
terdon
2
@terdon, salah satu bash kamu salah. bash sebelum 4.3 akan mengikuti symlinks saat turun. Juga bash tidak memiliki padanan untuk (.)kualifikasi globbing sehingga tidak dapat digunakan di sini. (Anda melewatkan beberapa - juga). Untuk loop tidak benar (hilang -r) dan berarti membuat beberapa lintasan dalam file dan tidak menambah manfaat atas skrip sed.
Stéphane Chazelas
7
@terdon Apa yang ditunjukkan --setelah sed -idan sebelum perintah pengganti?
Geek
5
@Geek itu hal POSIX. Ini menandakan akhir opsi dan memungkinkan Anda memberikan argumen yang dimulai dengan -. Menggunakannya memastikan bahwa perintah akan bekerja pada file dengan nama seperti -foo. Tanpa itu, -fakan diurai sebagai opsi.
terdon
1
Berhati-hatilah dalam mengeksekusi beberapa perintah rekursif di repositori git. Sebagai contoh, solusi yang disediakan di bagian 1 dari jawaban ini sebenarnya akan memodifikasi file git internal dalam .gitdirektori, dan benar-benar mengacaukan checkout Anda. Lebih baik beroperasi dalam / pada direktori tertentu dengan nama.
Pistos
75

A good r e pl acement alat Linux adalah RPL , yang pada awalnya ditulis untuk proyek Debian, sehingga tersedia dengan apt-get install rpldalam Debian berasal distro, dan mungkin bagi orang lain, tapi jika tidak Anda dapat men-download tar.gzfile dalam SourgeForge .

Contoh penggunaan paling sederhana:

 $ rpl old_string new_string test.txt

Perhatikan bahwa jika string berisi spasi, ia harus dilampirkan dalam tanda kutip. Secara default rplmengurus huruf kapital tetapi bukan dari kata-kata lengkap , tetapi Anda dapat mengubah default ini dengan pilihan -i(mengabaikan kasus) dan -w(seluruh kata-kata). Anda juga dapat menentukan beberapa file :

 $ rpl -i -w "old string" "new string" test.txt test2.txt

Atau bahkan menentukan ekstensi ( -x) untuk mencari atau bahkan mencari secara rekursif ( -R) di direktori:

 $ rpl -x .html -x .txt -R old_string new_string test*

Anda juga dapat mencari / mengganti dalam mode interaktif dengan -popsi (cepat):

Outputnya menunjukkan jumlah file / string yang diganti dan jenis pencarian (huruf dalam / sensitif, seluruh / sebagian kata), tetapi bisa diam dengan opsi -q( mode senyap ), atau bahkan lebih verbose, daftar nomor baris yang berisi cocok dengan setiap file dan direktori dengan opsi -v( mode verbose ).

Opsi lain yang patut diingat adalah -e(honor e scapes) yang memungkinkan regular expressions, sehingga Anda juga dapat mencari tabs ( \t), baris baru ( \n), dll. Bahkan Anda dapat menggunakan -funtuk memaksa izin (tentu saja, hanya ketika pengguna memiliki izin menulis) dan -duntuk menjaga waktu modifikasi`).

Akhirnya, jika Anda tidak yakin akan membuat yang tepat, gunakan -s( mode simulasi ).

Fran
sumber
2
Jauh lebih baik pada umpan balik dan kesederhanaan daripada sed. Saya hanya berharap itu diperbolehkan bertindak atas nama file, dan kemudian akan sempurna apa adanya.
Kzqai
1
Saya suka -s (mode simulasi) :-)
erm3nda
25

Cara melakukan pencarian dan mengganti lebih dari beberapa file menyarankan:

Anda juga bisa menggunakan find dan sed, tetapi saya menemukan bahwa garis kecil perl ini bekerja dengan baik.

perl -pi -w -e 's/search/replace/g;' *.php
  • -e berarti menjalankan baris kode berikut.
  • -i berarti mengedit di tempat
  • -w menulis peringatan
  • -p loop di atas file input, mencetak setiap baris setelah script diterapkan padanya.

Hasil terbaik saya berasal dari menggunakan perl dan grep (untuk memastikan file memiliki ekspresi pencarian)

perl -pi -w -e 's/search/replace/g;' $( grep -rl 'search' )
Alejandro Salamanca Mazuelo
sumber
13

Anda dapat menggunakan Vim dalam mode Ex:

ganti string ALF dengan BRA di semua file di direktori saat ini?

for CHA in *
do
  ex -sc '%s/ALF/BRA/g' -cx "$CHA"
done

melakukan hal yang sama secara rekursif untuk sub direktori?

find -type f -exec ex -sc '%s/ALF/BRA/g' -cx {} ';'

ganti hanya jika nama file cocok dengan string lain?

for CHA in *.txt
do
  ex -sc '%s/ALF/BRA/g' -cx "$CHA"
done

ganti hanya jika string ditemukan dalam konteks tertentu?

ex -sc 'g/DEL/s/ALF/BRA/g' -cx file

ganti jika string ada pada nomor baris tertentu?

ex -sc '2s/ALF/BRA/g' -cx file

ganti beberapa string dengan penggantian yang sama

ex -sc '%s/\vALF|ECH/BRA/g' -cx file

ganti beberapa string dengan penggantian yang berbeda

ex -sc '%s/ALF/BRA/g|%s/FOX/GOL/g' -cx file
Steven Penny
sumber
13

Saya menggunakan ini:

grep -r "old_string" -l | tr '\n' ' ' | xargs sed -i 's/old_string/new_string/g'
  1. Daftar semua file yang berisi old_string.

  2. Ganti baris baru dalam hasil dengan spasi (sehingga daftar file dapat diumpankan ke sed.

  3. Jalankan sedpada file-file itu untuk mengganti string lama dengan yang baru.

Pembaruan: Hasil di atas akan gagal pada nama file yang mengandung spasi putih. Sebaliknya, gunakan:

grep --null -lr "old_string" | xargs --null sed -i 's/old_string/new_string/g'

o_o_o--
sumber
Perhatikan bahwa ini akan gagal jika salah satu dari nama file Anda berisi spasi, tab atau baris baru. Penggunaan grep --null -lr "old_string" | xargs --null sed -i 's/old_string/new_string/g'akan membuatnya berurusan dengan nama file yang sewenang-wenang.
terdon
terima kasih kawan menambahkan pembaruan dan meninggalkan kode lama karena itu peringatan yang menarik yang dapat berguna bagi seseorang yang tidak mengetahui perilaku ini.
o_o_o--
6

Dari perspektif pengguna, alat Unix yang bagus & sederhana yang melakukan pekerjaan dengan sempurna qsubst. Sebagai contoh,

% qsubst foo bar *.c *.h

akan diganti foodengan bardi semua file C saya. Fitur yang bagus adalah yang qsubstakan melakukan query-replace , yaitu, ia akan menunjukkan kepada saya setiap kemunculan foodan bertanya apakah saya ingin menggantinya atau tidak. [Anda dapat mengganti tanpa syarat (tanpa bertanya) dengan -goopsi, dan ada opsi lain, misalnya, -wjika Anda hanya ingin mengganti fooketika itu merupakan keseluruhan kata.]

Cara mendapatkannya: qsubstditemukan oleh der Mouse (dari McGill) dan diposting ke comp.unix.sources 11 (7) pada Agustus 1987. Versi yang diperbarui ada. Sebagai contoh, versi NetBSD qsubst.c,v 1.8 2004/11/01mengkompilasi dan berjalan dengan sempurna di mac saya.

phs
sumber
2

Saya membutuhkan sesuatu yang akan memberikan opsi lari-kering dan akan bekerja secara rekursif dengan bola, dan setelah mencoba melakukannya dengan awkdan sedsaya menyerah dan bukannya melakukannya dengan python.

The Script mencari rekursif semua file yang cocok dengan pola glob (misalnya --glob="*.html") untuk regex dan menggantikan dengan regex pengganti:

find_replace.py [--dir=my_folder] \
    --search-regex=<search_regex> \
    --replace-regex=<replace_regex> \
    --glob=[glob_pattern] \
    --dry-run

Setiap opsi panjang seperti --search-regexmemiliki opsi pendek yang sesuai, yaitu -s. Jalankan dengan -huntuk melihat semua opsi.

Misalnya, ini akan membalik semua tanggal dari 2017-12-31ke 31-12-2017:

python replace.py --glob=myfile.txt \
    --search-regex="(\d{4})-(\d{2})-(\d{2})" \
    --replace-regex="\3-\2-\1" \
    --dry-run --verbose
import os
import fnmatch
import sys
import shutil
import re

import argparse

def find_replace(cfg):
    search_pattern = re.compile(cfg.search_regex)

    if cfg.dry_run:
        print('THIS IS A DRY RUN -- NO FILES WILL BE CHANGED!')

    for path, dirs, files in os.walk(os.path.abspath(cfg.dir)):
        for filename in fnmatch.filter(files, cfg.glob):

            if cfg.print_parent_folder:
                pardir = os.path.normpath(os.path.join(path, '..'))
                pardir = os.path.split(pardir)[-1]
                print('[%s]' % pardir)
            filepath = os.path.join(path, filename)

            # backup original file
            if cfg.create_backup:
                backup_path = filepath + '.bak'

                while os.path.exists(backup_path):
                    backup_path += '.bak'
                print('DBG: creating backup', backup_path)
                shutil.copyfile(filepath, backup_path)

            with open(filepath) as f:
                old_text = f.read()

            all_matches = search_pattern.findall(old_text)

            if all_matches:

                print('Found {} matches in file {}'.format(len(all_matches), filename))

                new_text = search_pattern.sub(cfg.replace_regex, old_text)

                if not cfg.dry_run:
                    with open(filepath, "w") as f:
                        print('DBG: replacing in file', filepath)
                        f.write(new_text)
                else:
                    for idx, matches in enumerate(all_matches):
                        print("Match #{}: {}".format(idx, matches))

                    print("NEW TEXT:\n{}".format(new_text))

            elif cfg.verbose:
                print('File {} does not contain search regex "{}"'.format(filename, cfg.search_regex))


if __name__ == '__main__':

    parser = argparse.ArgumentParser(description='''DESCRIPTION:
    Find and replace recursively from the given folder using regular expressions''',
                                     formatter_class=argparse.RawDescriptionHelpFormatter,
                                     epilog='''USAGE:
    {0} -d [my_folder] -s <search_regex> -r <replace_regex> -g [glob_pattern]

    '''.format(os.path.basename(sys.argv[0])))

    parser.add_argument('--dir', '-d',
                        help='folder to search in; by default current folder',
                        default='.')

    parser.add_argument('--search-regex', '-s',
                        help='search regex',
                        required=True)

    parser.add_argument('--replace-regex', '-r',
                        help='replacement regex',
                        required=True)

    parser.add_argument('--glob', '-g',
                        help='glob pattern, i.e. *.html',
                        default="*.*")

    parser.add_argument('--dry-run', '-dr',
                        action='store_true',
                        help="don't replace anything just show what is going to be done",
                        default=False)

    parser.add_argument('--create-backup', '-b',
                        action='store_true',
                        help='Create backup files',
                        default=False)

    parser.add_argument('--verbose', '-v',
                        action='store_true',
                        help="Show files which don't match the search regex",
                        default=False)

    parser.add_argument('--print-parent-folder', '-p',
                        action='store_true',
                        help="Show the parent info for debug",
                        default=False)

    config = parser.parse_args(sys.argv[1:])

    find_replace(config)

Here adalah versi terbaru dari skrip yang menyoroti istilah pencarian dan penggantian dengan warna yang berbeda.

ccpizza
sumber
1
Saya tidak mengerti mengapa Anda membuat sesuatu yang kompleks ini. Untuk rekursi, gunakan globstaropsi bash (atau yang setara dengan shell Anda) dan **gumpalan atau find. Untuk lari kering, gunakan saja sed. Kecuali Anda menggunakan -iopsi, itu tidak akan membuat perubahan. Untuk penggunaan cadangan sed -i.bak(atau perl -i .bak); untuk file yang tidak cocok, gunakan grep PATTERN file || echo file. Dan mengapa di dunia Anda ingin python memperluas gumpalan alih-alih membiarkan shell melakukannya? Kenapa script.py --glob=foo*bukannya adil script.py foo*?
terdon
1
Mengapa saya sangat sederhana: (1) di atas semua, kemudahan debugging; (2) hanya menggunakan satu alat yang terdokumentasi dengan baik dengan komunitas yang mendukung (3) tidak mengetahui seddan awksehat dan tidak mau menginvestasikan waktu ekstra untuk menguasainya, (4) keterbacaan, (5) solusi ini juga akan bekerja pada sistem non-posix (Bukan karena aku butuh itu tapi orang lain mungkin).
ccpizza
1

ripgrep (nama perintah rg) adalah grepalat, tetapi mendukung pencarian dan ganti juga.

$ cat ip.txt
dark blue and light blue
light orange
blue sky
$ # by default, line number is displayed if output destination is stdout
$ # by default, only lines that matched the given pattern is displayed
$ # 'blue' is search pattern and -r 'red' is replacement string
$ rg 'blue' -r 'red' ip.txt
1:dark red and light red
3:red sky

$ # --passthru option is useful to print all lines, whether or not it matched
$ # -N will disable line number prefix
$ # this command is similar to: sed 's/blue/red/g' ip.txt
$ rg --passthru -N 'blue' -r 'red' ip.txt
dark red and light red
light orange
red sky


rg tidak mendukung opsi di tempat, jadi Anda harus melakukannya sendiri

$ # -N isn't needed here as output destination is a file
$ rg --passthru 'blue' -r 'red' ip.txt > tmp.txt && mv tmp.txt ip.txt
$ cat ip.txt
dark red and light red
light orange
red sky


Lihat dokumentasi Rust regex untuk sintaks dan fitur ekspresi reguler. The -Pswitch akan memungkinkan PCRE2 rasa. rgmendukung Unicode secara default.

$ # non-greedy quantifier is supported
$ echo 'food land bark sand band cue combat' | rg 'foo.*?ba' -r 'X'
Xrk sand band cue combat

$ # unicode support
$ echo 'fox:αλεπού,eagle:αετός' | rg '\p{L}+' -r '($0)'
(fox):(αλεπού),(eagle):(αετός)

$ # set operator example, remove all punctuation characters except . ! and ?
$ para='"Hi", there! How *are* you? All fine here.'
$ echo "$para" | rg '[[:punct:]--[.!?]]+' -r ''
Hi there! How are you? All fine here.

$ # use -P if you need even more advanced features
$ echo 'car bat cod map' | rg -P '(bat|map)(*SKIP)(*F)|\w+' -r '[$0]'
[car] bat [cod] map


Seperti grep, -Fopsi akan memungkinkan string tetap untuk dicocokkan, opsi praktis yang saya rasa sedharus diterapkan juga.

$ printf '2.3/[4]*6\nfoo\n5.3-[4]*9\n' | rg --passthru -F '[4]*' -r '2'
2.3/26
foo
5.3-29


Opsi praktis lainnya adalah -Uyang memungkinkan pencocokan multiline

$ # (?s) flag will allow . to match newline characters as well
$ printf '42\nHi there\nHave a Nice Day' | rg --passthru -U '(?s)the.*ice' -r ''
42
Hi  Day


rg dapat menangani file dos-style juga

$ # same as: sed -E 's/\w+(\r?)$/123\1/'
$ printf 'hi there\r\ngood day\r\n' | rg --passthru --crlf '\w+$' -r '123'
hi 123
good 123


Keuntungan lain rgadalah kemungkinan lebih cepat daripadased

$ # for small files, initial processing time of rg is a large component
$ time echo 'aba' | sed 's/a/b/g' > f1
real    0m0.002s
$ time echo 'aba' | rg --passthru 'a' -r 'b' > f2
real    0m0.007s

$ # for larger files, rg is likely to be faster
$ # 6.2M sample ASCII file
$ wget https://norvig.com/big.txt    
$ time LC_ALL=C sed 's/\bcat\b/dog/g' big.txt > f1
real    0m0.060s
$ time rg --passthru '\bcat\b' -r 'dog' big.txt > f2
real    0m0.048s
$ diff -s f1 f2
Files f1 and f2 are identical

$ time LC_ALL=C sed -E 's/\b(\w+)(\s+\1)+\b/\1/g' big.txt > f1
real    0m0.725s
$ time rg --no-pcre2-unicode --passthru -wP '(\w+)(\s+\1)+' -r '$1' big.txt > f2
real    0m0.093s
$ diff -s f1 f2
Files f1 and f2 are identical
Sundeep
sumber