파일에서 문자열을 바꾸려면 어떻게해야합니까?


752

특정 검색 기준에 따라 파일에서 문자열을 바꾸는 것은 매우 일반적인 작업입니다. 내가 어떻게 할 수있는

  • 현재 디렉토리의 모든 파일에서 문자열 foo을 바꾸 bar시겠습니까?
  • 하위 디렉토리에 대해서도 동일하게 반복합니까?
  • 파일 이름이 다른 문자열과 일치하는 경우에만 바꾸시겠습니까?
  • 문자열이 특정 상황에서 발견 된 경우에만 교체 하시겠습니까?
  • 문자열이 특정 줄 번호에 있으면 바꾸시겠습니까?
  • 여러 개의 문자열을 같은 것으로 교체하십시오
  • 여러 문자열을 다른 대체물로 대체

2
이것은이 주제에 대한 정식 Q & A를위한 것입니다 (이 메타 토론 참조 ). 아래 답변을 편집하거나 직접 추가하십시오.
terdon

답변:


1010

1. 현재 디렉토리의 모든 파일에서 한 문자열을 모두 다른 문자열로 바꿉니다.

어디 이러한 경우에 있습니다 알고 디렉토리가 정규 파일이 포함되어 있고 모든 비 숨겨진 파일을 처리 할 것인지. 그렇지 않은 경우 2의 방법을 사용하십시오.

sed이 답변의 모든 솔루션은 GNU를 가정 sed합니다. FreeBSD의 또는 OS / X를 사용하는 경우, 교체 -i와 함께 -i ''. 또한 -i모든 버전의 스위치와 함께 스위치를 사용하면 sed특정 파일 시스템 보안에 영향 을 미치며 어떤 방식 으로든 배포하려는 모든 스크립트에서 권장되지 않습니다.

  • 이 디렉토리의 비 재귀 파일 만 :

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

    ( perl파일 이름이 |공백으로 끝나는 경우 실패합니다 ).

  • 이 디렉토리와 모든 서브 디렉토리의 재귀적이고 규칙적인 파일 ( 숨겨진 파일 포함 )

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

    zsh를 사용하는 경우 :

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

    목록이 너무 크면 실패 할 수 있습니다 ( zargs해결 방법 참조 ).

    Bash는 일반 파일을 직접 확인할 수 없으며 루프가 필요합니다 (중괄호는 옵션을 전체적으로 설정하지 마십시오)

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

    파일은 실제 파일 (-f)이고 쓰기 가능 (-w) 일 때 선택됩니다.

2. 파일 이름이 다른 문자열과 일치하거나 특정 확장자가 있거나 특정 유형 인 경우에만 교체하십시오.

  • 이 디렉토리의 비 재귀 파일 만 :

    sed -i -- 's/foo/bar/g' *baz*    ## all files whose name contains baz
    sed -i -- 's/foo/bar/g' *.baz    ## files ending in .baz
    
  • 이 디렉토리와 모든 서브 디렉토리의 재귀적이고 규칙적인 파일

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

    bash를 사용하는 경우 (괄호는 옵션을 전체적으로 설정하지 마십시오) :

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

    zsh를 사용하는 경우 :

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

    --가 게재 알 수 있습니다 sed더 이상의 플래그가 명령 줄에서 주어되지 않습니다 것을. 이는로 시작하는 파일 이름으로부터 보호하는 데 유용합니다 -.

  • 파일이 특정 유형 (예 : 실행 파일) 인 경우 ( man find추가 옵션 참조 ) :

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

    zsh:

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

3. 문자열이 특정 상황에서 발견 된 경우에만 교체

  • 교체 foobar가있는 경우에만 baz같은 줄에 이상 :

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

    에서은 sed, 사용은 \( \)괄호에 당신이 다음에 액세스 할 수 있습니다 어떤 저장 \1. 이러한 정규 표현식에 대해 자세히 알아 보려면이 테마에 여러 변형이 있습니다 ( 여기 참조) .

  • 장착 foobar경우에만 foo입력 파일의 3D 항목 (필드)에서 발견된다 (공백 구분 필드를 가정)

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

    ( gawk4.1.0 이상 필요 )

  • 다른 필드의 경우 관심 필드의 수는 $Nwhere를 사용 N하십시오. 다른 필드 구분 기호 ( :이 예에서는)를 사용하십시오.

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

    다음을 사용하는 다른 솔루션 perl:

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

    참고 : awkperl솔루션 모두 파일의 간격에 영향을줍니다 (앞 및 뒤 공백을 제거하고 해당 행에서 공백 문자를 공백 문자 하나로 변환). 다른 필드의 경우 원하는 필드 번호는 $F[N-1]어디에 N있고 다른 필드 구분 기호 $"=":"는 출력 필드 구분 기호를으로 설정하십시오 :.

    perl -i -F':' -ane '$F[2]=~s/foo/baz/g; $"=":";print "@F"' foo 
  • 교체 foobar만 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. 여러 바꾸기 작업 : 다른 문자열로 교체

  • sed명령 을 결합 할 수 있습니다 .

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

    주문 사항은 (주의하십시오 sed 's/foo/bar/g; s/bar/baz/g'대체 할 foobaz).

  • 또는 Perl 명령

    perl -i -pe 's/foo/bar/g; s/baz/zab/g; s/Alice/Joan/g' file
  • 패턴이 많은 경우 패턴 및 대체 패턴을 sed스크립트 파일 에 저장하는 것이 더 쉽습니다 .

    #! /usr/bin/sed -f
    s/foo/bar/g
    s/baz/zab/g
    
  • 또는 위의 방법을 사용할 수있는 패턴 쌍이 너무 많은 경우 파일에서 패턴 쌍을 읽을 수 있습니다 (한 줄에 공백으로 구분 된 두 패턴, $ pattern 및 $ replacement).

    while read -r pattern replacement; do   
        sed -i "s/$pattern/$replacement/" file
    done < patterns.txt
    
  • 긴 패턴 목록과 큰 데이터 파일의 경우 속도가 느려서 패턴을 읽고 sed대신 스크립트를 작성할 수 있습니다 . 다음은 <space> 구분자 가 파일에서 한 줄에 하나씩 발생하는 MATCH <space> REPLACE 쌍 목록을 분리 한다고 가정 합니다 patterns.txt.

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

    위 형식은 대부분 임의적이며, 예를 들어 MATCH 또는 REPLACE 에서 <space> 를 허용하지 않습니다 . 이 방법은 매우 일반적입니다. 기본적으로 스크립트 처럼 보이는 출력 스트림을 만들 수있는 경우 의 스크립트 파일을 stdin 으로 지정하여 해당 스트림을 스크립트 로 소싱 할 수 있습니다 .sedsedsed-

  • 비슷한 방식으로 여러 스크립트를 결합하고 연결할 수 있습니다.

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

    POSIX sed는 모든 스크립트를 명령 행에 나타나는 순서대로 하나로 연결합니다. 이들 중 어느 것도 \n유선으로 끝나지 않아도됩니다.

  • grep 같은 방식으로 작동 할 수 있습니다 :

    sed -e'#generate a pattern list' <in |
    grep -f- ./grepped_file
    
  • 고정 문자열을 패턴으로 작업 할 때는 정규식 메타 문자 를 피하는 것이 좋습니다 . 오히려 쉽게 할 수 있습니다.

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

5. 복수 교체 작업 : 동일한 문자열로 여러 패턴 교체

  • 의 교체 foo, bar또는 bazfoobar

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

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

2
@ StéphaneChazelas 편집 해 주셔서 감사합니다. 실제로 몇 가지 사항을 수정했습니다. 그러나 bash와 관련된 정보는 제거하지 마십시오. 모든 사람이 사용하는 것은 아닙니다 zsh. 꼭 zsh정보를 추가 하되 배쉬를 제거 할 이유는 없습니다. 또한 텍스트 처리에 쉘을 사용하는 것이 이상적이지 않지만 필요한 경우가 있다는 것을 알고 있습니다. sed실제로 쉘 루프를 사용하여 구문 분석하는 대신 스크립트를 작성하는 더 나은 버전의 원본 스크립트를 편집했습니다 . 예를 들어 수백 쌍의 패턴이있는 경우 유용 할 수 있습니다.
terdon

2
@ terdon, bash 하나가 잘못되었습니다. 4.3 이전의 bash는 내려갈 때 심볼릭 링크를 따릅니다. 또한 bash는 (.)globbing 한정자에 해당 하지 않으므로 여기서 사용할 수 없습니다. (일부 빠진 것도 있습니다). for 루프는 정확하지 않으며 (-r 누락) 파일에 여러 번 패스하는 것을 의미하며 sed 스크립트에 비해 이점이 없습니다.
Stéphane Chazelas

7
@terdon 대체 명령 --이후 sed -i와 무엇을 나타내는가 ?
Geek

5
@Geek 그것은 POSIX 일입니다. 옵션의 끝을 나타내며로 시작하는 인수를 전달할 수 있습니다 -. 이 명령을 사용하면 이름이 같은 파일에서 명령이 작동합니다 -foo. 그렇지 않으면 -f옵션으로 구문 분석됩니다.
terdon

1
git 저장소에서 재귀 명령 중 일부를 실행하는 데 매우주의하십시오. 예를 들어,이 답변의 섹션 1에 제공된 솔루션은 실제로 .git디렉토리의 내부 git 파일을 수정 하고 실제로 체크 아웃을 엉망으로 만듭니다. 특정 디렉토리 내에서 / 이름으로 작업하는 것이 더 좋습니다.
Pistos

75

좋은 r에 전자 PL acement 리눅스 도구입니다 RPL 은 함께 사용할 수 있도록 그 원래, 데비안 프로젝트를 위해 작성되었으며, apt-get install rpl어떠한 데비안 파생 된 배포판에서, 그리고 다른 사람이 될 수 있지만, 그렇지 않으면 당신은 다운로드 할 수 있습니다 tar.gz에서 파일을 SourgeForge .

가장 간단한 사용 예 :

 $ rpl old_string new_string test.txt

문자열에 공백이 있으면 따옴표로 묶어야합니다. 기본적 rpl으로 대문자 는 처리 하지만 완전한 단어 는 처리하지 않지만 옵션 -i(대소 문자 무시) 및 -w(전체 단어)를 사용 하여 이러한 기본값을 변경할 수 있습니다 . 여러 파일을 지정할 수도 있습니다 .

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

또는 확장명 ( -x)을 지정 하여 디렉토리에서 검색하거나 재귀 적 으로 검색 할 수도 있습니다 ( -R).

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

(프롬프트) 옵션을 사용 하여 대화식 모드 에서 검색 / 대체 할 수도 -p있습니다.

출력에는 대체 된 파일 / 문자열 수와 검색 유형 (대소 문자 구분 / 대소 문자 구분, 전체 / 부분 단어)이 표시되지만 -q( 조용한 모드 ) 옵션을 사용하여 더 조용 하거나 더 자세한 내용을 포함하는 행 번호를 나열 할 수 있습니다. -v( verbose mode ) 옵션을 사용 하여 각 파일 및 디렉토리와 일치합니다 .

기억할만한 가치가있는 다른 옵션은 -e(명예의 전자 수있는 작품 Scapes) regular expressions, 그래서 당신은 또한 탭 (검색 할 수 있습니다 \t), 새로운 라인 ( \n등). 심지어 권한-f강요 하고 (사용자가 쓰기 권한을 가지고있을 -d때만) 수정 시간을 보존하는 데 사용할 수 있습니다.

마지막으로, 어느 것이 정확하게 만들어 질지 확실하지 않으면 -s( 시뮬레이션 모드 )를 사용하십시오 .


2
sed보다 피드백과 단순성이 훨씬 뛰어납니다. 파일 이름으로 작동하도록 허용 한 다음 그대로 사용하면 좋을 것입니다.
Kzqai

1
나는 -s (시뮬레이션 모드)를 좋아한다 :-)
erm3nda

25

여러 파일을 검색하고 바꾸는 방법은 다음과 같습니다.

find와 sed를 사용할 수도 있지만이 작은 펄 라인은 훌륭하게 작동합니다.

perl -pi -w -e 's/search/replace/g;' *.php
  • -e는 다음 코드 줄을 실행하는 것을 의미합니다.
  • -i는 내부 편집을 의미합니다
  • -w 경고 쓰기
  • -p 입력 파일을 반복하여 스크립트가 적용된 후 각 줄을 인쇄합니다.

내 최고의 결과는 perl과 grep을 사용하여 얻은 것입니다 (파일에 검색 표현식이 있는지 확인하기 위해)

perl -pi -w -e 's/search/replace/g;' $( grep -rl 'search' )

13

Ex 모드에서 Vim을 사용할 수 있습니다 :

현재 디렉토리의 모든 파일에서 문자열 ALF를 BRA로 바꾸시겠습니까?

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

하위 디렉토리에 대해서도 동일하게 반복합니까?

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

파일 이름이 다른 문자열과 일치하는 경우에만 바꾸시겠습니까?

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

문자열이 특정 상황에서 발견 된 경우에만 교체 하시겠습니까?

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

문자열이 특정 줄 번호에 있으면 바꾸시겠습니까?

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

여러 개의 문자열을 같은 것으로 교체하십시오

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

여러 문자열을 다른 대체물로 대체

ex -sc '%s/ALF/BRA/g|%s/FOX/GOL/g' -cx file

13

나는 이것을 사용했다 :

grep -r "old_string" -l | tr '\n' ' ' | xargs sed -i 's/old_string/new_string/g'
  1. 가 포함 된 모든 파일을 나열하십시오 old_string.

  2. 결과로 개행을 공백으로 바꾸십시오 (파일 목록이에 제공 될 수 있도록) sed.

  3. sed해당 파일에서 실행 하여 이전 문자열을 새 문자열로 바꿉니다.

업데이트 : 위의 결과는 공백이 포함 된 파일 이름에서 실패합니다. 대신 다음을 사용하십시오.

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


파일 이름에 공백, 탭 또는 줄 바꿈이 포함되어 있으면 실패합니다. 사용 grep --null -lr "old_string" | xargs --null sed -i 's/old_string/new_string/g'하면 임의의 파일 이름을 처리하게됩니다.
terdon

고마워 업데이트를 추가하고 이전 코드를 남겨두면이 동작을 알지 못하는 사람에게 유용 할 수있는 흥미로운 경고가됩니다.
o_o_o--

6

사용자 관점에서 작업을 완벽하게 수행하는 훌륭하고 간단한 유닉스 도구는 qsubst입니다. 예를 들어

% qsubst foo bar *.c *.h

내 모든 C 파일로 대체 foo됩니다 bar. 좋은 기능은 query-replace를qsubst 수행하는 것입니다 . 즉, 각 발생을 표시 하고 교체할지 여부를 묻습니다. [무조건적으로 (요구하지 않고) 옵션 으로 대체 할 수 있으며 다른 단어가 있습니다 (예 : 전체 단어 일 때만 바꾸려는 경우).foo-go-wfoo

얻는 방법 : qsubstder Mouse (McGill)가 발명하고 1987 년 8 월 에 comp.unix.sources 11 (7) 에 게시했습니다 . 업데이트 된 버전이 있습니다. 예를 들어, NetBSD 버전 qsubst.c,v 1.8 2004/11/01은 내 Mac에서 컴파일되고 완벽하게 실행됩니다.


2

나는 드라이 실행 옵션을 제공 할 것와 글로브와 함께 반복적으로 작업 할 것이며, 함께 일을하려고 후 무언가를 필요로 awk하고 sed내가 포기하고 대신 파이썬에서 그것을했다.

스크립트는 글로브 패턴 (예를 들어 일치하는 재귀 적으로 모든 파일 검색 --glob="*.html"정규식에 대한)을하고 교체 정규 표현식으로 대체합니다 :

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

와 같은 모든 긴 옵션 --search-regex에는 해당하는 짧은 옵션이 -s있습니다. -h모든 옵션을 보려면 다음을 실행 하십시오.

예를 들어, 이것은 모든 날짜를에서 2017-12-31로 바꿉니다 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 검색어와 다른 색상으로 대체 된 내용을 강조 표시하는 업데이트 된 버전의 스크립트입니다.


1
왜이 복잡한 것을 만들지 모르겠습니다. 재귀의 경우 bash 또는 쉘과 동등한 globstar옵션과 **globs 또는를 사용하십시오 find. 드라 이런을하려면을 사용하십시오 sed. -i옵션 을 사용하지 않으면 변경되지 않습니다. 백업용 sed -i.bak(또는 perl -i .bak); 일치하지 않는 파일의 경우을 사용하십시오 grep PATTERN file || echo file. 그리고 왜 세상에서 파이썬이 쉘을 허용하지 않고 글로브를 확장하게 하시겠습니까? 왜 script.py --glob=foo*대신에 script.py foo*?
terdon

1
이유 는 매우 간단합니다. (1) 무엇보다도 디버깅 용이성; (2) 지원 커뮤니티 (3) 모르고 만 하나 잘 문서화 도구 사용 sedawk(5)이 솔루션은 또한 비 POSIX 시스템에서 작동, (4) 가독성, 잘 그들을 마스터에 여분의 시간을 투자 내키지 인을 (필요하지는 않지만 다른 사람이 필요할 수도 있음).
ccpizza

1

ripgrep (command name rg)은 grep도구이지만 검색 및 바꾸기도 지원합니다.

$ 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 적절한 옵션을 지원하지 않으므로 직접해야합니다.

$ # -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


정규식 구문 및 기능에 대해서는 Rust 정규식 문서 를 참조하십시오 . -P스위치를 가능하게 할 것이다 PCRE2의 맛을. rg기본적으로 유니 코드를 지원합니다.

$ # 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


처럼 grep, -F옵션은 고정 문자열을 일치시킬 수 있으며, 내가 sed구현해야 할 편리한 옵션입니다 .

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


또 다른 편리한 옵션은 여러 줄 -U일치를 가능하게하는 것입니다

$ # (?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 도스 스타일 파일도 처리 할 수 ​​있습니다

$ # 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


다른 장점은 rg보다 빠를 가능성이 있다는 것입니다sed

$ # 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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.