여러 패턴을 한 번에 sed로 바꾸는 방법은 무엇입니까?


231

'abbc'문자열이 있고 바꾸고 싶다고 가정 해보십시오.

  • ab-> 기원전
  • bc-> ab

두 번 교체하려고하면 결과가 원하는 것이 아닙니다.

echo 'abbc' | sed 's/ab/bc/g;s/bc/ab/g'
abab

그렇다면 아래와 같이 대체 할 수있는 sed 명령은 무엇입니까?

echo abbc | sed SED_COMMAND
bcab

편집 : 실제로 텍스트에는 2 개 이상의 패턴이있을 수 있으며 필요한 교체 수를 알 수 없습니다. sed스트림 편집기 라는 답변이 있었고 그 대체품은 탐욕스럽게 생각하기 때문에 스크립트 언어를 사용해야한다고 생각합니다.


같은 줄에 여러 번 교체해야합니까? g두 s///명령 모두 에서 플래그를 삭제하지 않으면 작동합니다.
— Etan Reisner 1

내 질문의 요점을 놓쳤다. 같은 줄에 각 교체품을 두 번 이상 만들어야한다는 의미 입니다. 원래 입력에 대해 ab 또는 둘 이상의 일치 항목이 있습니까? bc
— Etan Reisner

죄송합니다 @EtanReisner 내가 오해했습니다, 답변은 예입니다. 텍스트가 여러 번 대체 될 수 있습니다.
— DaniloNC

답변:


342

아마도 이런 식으로 뭔가 :

sed 's/ab/~~/g; s/bc/ab/g; s/~~/bc/g'

~문자열에없는 문자로 바꿉니다 .


9
GNU는 핸들의 NUL을을 나오지도, 그래서 당신은 사용할 수 있습니다 \x0에 대한 ~~.
— jthill

3
가 g필요하고 어떤 역할을합니까?
— Lee

12
@Lee g는 전역을위한 것입니다-첫 행 (기본 동작) 대신 각 행의 패턴 인스턴스를 모두 바꿉니다.
— naught101

1
여러 조합을 동시에 대체 할 수있는 ooga의 답변 변형에 대해서는 내 답변 stackoverflow.com/a/41273117/539149 를 참조하십시오 .
— 잭 모리스

3
당신이 문자열에되지 않습니다 알고 생산 코드의 경우, 입력에 대한 가정을하지 않습니다. 테스트의 경우 테스트가 실제로 정확성을 입증하는 것은 아니지만 테스트를위한 좋은 아이디어는 다음과 같습니다. 스크립트 자체를 입력으로 사용하십시오.
— hagello

33

나는 항상 "-e"와 함께 여러 문장을 사용한다

$ sed -e 's:AND:\n&:g' -e 's:GROUP BY:\n&:g' -e 's:UNION:\n&:g' -e 's:FROM:\n&:g' file > readable.sql

이것은 모든 AND, GROUP BY, UNION 및 FROM 앞에 '\ n'을 추가하는 반면 '&'는 일치하는 문자열을 의미하고 '\ n &'은 일치하는 문자열을 '\ n'앞에 '\ n'으로 바꾸려는 것을 의미합니다 '


14

다음은 값이 재사용되는 방법을 확인하지 않고 여러 검색 및 바꾸기 쌍에 작동 하는 ooga의 답변 변형입니다 .

sed -i '
s/\bAB\b/________BC________/g
s/\bBC\b/________CD________/g
s/________//g
' path_to_your_files/*.txt

예를 들면 다음과 같습니다.

전에:

some text AB some more text "BC" and more text.

후:

some text BC some more text "CD" and more text.

\b단어 경계를 나타내 ________므로 검색을 방해 하지 않습니다 (우분투에서 GNU sed 4.2.2를 사용하고 있습니다). 단어 경계 검색을 사용하지 않으면이 기술이 작동하지 않을 수 있습니다.

또한 명령을 제거 하고 명령 끝에 s/________//g추가 하는 것과 동일한 결과를 제공 && sed -i 's/________//g' path_to_your_files/*.txt하지만 경로를 두 번 지정할 필요는 없습니다.

jthill이 제안한 것처럼 파일에 null이 나타나지 않는다는 것을 알고 있다면 대신 사용 \x0하거나 _\x0_대신 사용할 ________수 있습니다 .


입력 내용에 포함될 수있는 가정을하지 않는 것에 대한 위의 hagello의 의견에 동의합니다. 따라서 저는 개인적으로 이것이 sed를 서로 뿌려주는 것 외에 가장 신뢰할 수있는 솔루션이라고 생각합니다 ( sed 's/ab/xy/' | sed 's/cd/ab/' .....)
— leetbacoon

12

sed스트림 편집기입니다. 탐욕스럽게 검색하고 교체합니다. 요청한 것을 수행하는 유일한 방법은 중간 대체 패턴을 사용하고 결국 다시 변경하는 것입니다.

echo 'abcd' | sed -e 's/ab/xy/;s/cd/ab/;s/xy/cd/'


4

이것은 당신을 위해 일할 수 있습니다 (GNU sed) :

sed -r '1{x;s/^/:abbc:bcab/;x};G;s/^/\n/;:a;/\n\n/{P;d};s/\n(ab|bc)(.*\n.*:(\1)([^:]*))/\4\n\2/;ta;s/\n(.)/\1\n/;ta' file

이 테이블은 보류 공간 (HS)에서 준비된 후 각 행에 추가되는 찾아보기 테이블을 사용합니다. 고유 한 마커 (이 경우 \n)는 줄의 시작 부분에 추가되며 줄 길이 전체에서 검색을 범프하는 방법으로 사용됩니다. 마커가 라인의 끝에 도달하면 프로세스가 완료되고 조회 테이블과 마커가 삭제됩니다.

NB 룩업 테이블은 시작시 준비되며 :대체 문자열과 충돌하지 않도록 선택된 두 번째 고유 마커 (이 경우 )를 준비합니다.

일부 의견 :

sed -r '
  # initialize hold with :abbc:bcab
  1 {
    x
    s/^/:abbc:bcab/
    x
  }

  G        # append hold to patt (after a \n)

  s/^/\n/  # prepend a \n

  :a

  /\n\n/ {
    P      # print patt up to first \n
    d      # delete patt & start next cycle
  }

  s/\n(ab|bc)(.*\n.*:(\1)([^:]*))/\4\n\2/
  ta       # goto a if sub occurred

  s/\n(.)/\1\n/  # move one char past the first \n
  ta       # goto a if sub occurred
'

테이블은 다음과 같이 작동합니다.

   **   **   replacement
:abbc:bcab
 **   **     pattern

3

단일 패턴 발생에 대한보다 간단한 접근법 일 수 있습니다. 다음과 같이 시도 할 수 있습니다. echo 'abbc'| sed 's / ab / bc /; s / bc / ab / 2'

내 출력 :

 ~# echo 'abbc' | sed 's/ab/bc/;s/bc/ab/2'
 bcab

여러 번 패턴이 나타나는 경우 :

sed 's/\(ab\)\(bc\)/\2\1/g'

예

~# cat try.txt
abbc abbc abbc
bcab abbc bcab
abbc abbc bcab

~# sed 's/\(ab\)\(bc\)/\2\1/g' try.txt
bcab bcab bcab
bcab bcab bcab
bcab bcab bcab

도움이 되었기를 바랍니다 !!


2

Tcl에는이 기능이 내장 되어 있습니다

$ tclsh
% string map {ab bc bc ab} abbc
bcab

이것은 현재 위치에서 시작하는 문자열 비교를 수행하여 문자열을 한 번에 한 문자 씩 걷는 것으로 작동합니다.

펄에서 :

perl -E '
    sub string_map {
        my ($str, %map) = @_;
        my $i = 0;
        while ($i < length $str) {
          KEYS:
            for my $key (keys %map) {
                if (substr($str, $i, length $key) eq $key) {
                    substr($str, $i, length $key) = $map{$key};
                    $i += length($map{$key}) - 1;
                    last KEYS;
                }
            }
            $i++;
        }
        return $str;
    }
    say string_map("abbc", "ab"=>"bc", "bc"=>"ab");
'
bcab

0

여기되어 awkoogas에 기초sed

echo 'abbc' | awk '{gsub(/ab/,"xy");gsub(/bc/,"ab");gsub(/xy/,"bc")}1'
bcab
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.