여러 패턴을 한 번에 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스트림 편집기 라는 답변이 있었고 그 대체품은 탐욕스럽게 생각하기 때문에 스크립트 언어를 사용해야한다고 생각합니다.


같은 줄에 여러 번 교체해야합니까? gs///명령 모두 에서 플래그를 삭제하지 않으면 작동합니다.
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.