Programing

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

lottogame 2020. 5. 18. 08:00
반응형

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


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

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

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

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

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

echo abbc | sed SED_COMMAND
bcab

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


아마도 이런 식으로 뭔가 :

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

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


나는 항상 "-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'으로 바꾸려는 것을 의미합니다. '


다음은 값이 재사용되는 방법을 확인하지 않고 여러 검색 및 바꾸기 쌍에 작동 하는 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_대신 사용하는 것이 변형입니다 .________


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

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


이것은 당신을 위해 일할 수 있습니다 (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

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

May be a simpler approach for single pattern occurrence you can try as below: echo 'abbc' | sed 's/ab/bc/;s/bc/ab/2'

My output:

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

For multiple occurrences of pattern:

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

Example

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

Hope this helps !!


Here is an awk based on oogas sed

echo 'abbc' | awk '{gsub(/ab/,"xy");gsub(/bc/,"ab");gsub(/xy/,"bc")}1'
bcab

참고URL : https://stackoverflow.com/questions/26568952/how-to-replace-multiple-patterns-at-once-with-sed

반응형