sed로 예약된 공간에 저장된 단어를 검색하는 방법은 무엇입니까?

sed로 예약된 공간에 저장된 단어를 검색하는 방법은 무엇입니까?

이것은 sed구체적인 질문입니다. 다른 도구를 사용하여 이 작업을 수행할 수 있다는 것을 잘 알고 있지만 지식을 확장하려고 합니다 sed.

sed스크립트에서 지정되지 않은 단어에 전역 따옴표(실제로는 역따옴표)를 어떻게 사용할 수 있나요 ? 단어는 예약된 공간에 저장됩니다.

내가 원하는 것은 이것이다:

s/word/`&`/g

그러나 비결은 wordsed 스크립트가 아닌 예약된 공간에 포함시키는 것입니다. 따라서 다음과 같이 보입니다.

H
g
s/^\(.*\)\n\(.*\)\1\(.*\)$/\2`\1`\3/

이는 참조할 것입니다.하나예약된 공간에서 예약어가 발생합니다. 인용하고 싶다모두g하지만 정적 정규식 대신 역참조를 사용하기 때문에 플래그를 추가할 수는 없습니다 .

H
g
s/^\(.*\)\n\(.*\)\1\(.*\)\1\(.*\)$/\2`\1`\3`\1`\4/

이는 단어의 두 발생을 처리하지만 한 번 실패하고 여러 발생은 무시됩니다.

나는 다음과 같이 깨끗하고 간단한 것을 사용할 수 있다고 생각했습니다.

s//`&`/g

하지만 이것은 마지막으로 사용한 것을 재사용합니다정규식, 일치하는 것이 아닙니다. (이건 말이 된다.)

sed내가 원하는 것을 할 수 있는 방법이 있나요 ? (사실은 내가회의에서 이것이 얼마나 쉬운지 알아보고 싶지만 perl여전히 에서 이를 수행하는 방법을 알고 싶습니다 sed. )


고쳐 쓰다

그렇지는 않다필요하지만 저는 이 질문을 할 때 제가 정확히 무엇을 하고 있었는지에 대한 배경 지식을 좀 더 제공해야 한다고 생각했습니다.

대용량 문서 텍스트 파일이 있는데 그 중 일부를 압축하여 테이블로 요약해야 합니다 asciidoc. 이는 Description:행 등 으로 인해 매우 쉬우므로 실제로 모든 구문 분석을 수행하는 Prototype:빠른 스크립트를 작성했습니다 . 잘 작동하지만 한 가지 누락된 점은 해당 줄에 나열된 매개변수와 일치하는 줄의 단어를 역따옴표로 표시 sed하고 싶다는 것입니다 . 프로토타입 라인은 다음과 같습니다:DescriptionPrototype

Prototype: some_words_here(and, arg, list,here)

내가 출력하는 테이블에는 200개가 넘는 항목이 있으며(소스 문서에는 이보다 훨씬 많은 텍스트가 포함되어 있음) 각 인수 목록에는 일치하는 단어를 인용하기 위해 백틱만 필요합니다.하나의철사. 더 까다로운 점은 일부 매개변수가 설명 줄에 없고, 일부 매개변수가 여러 번 나타나고, 일부 매개변수 목록이 비어 있다는 것입니다().

그러나 때때로 arg가 일치할 수도 있다는 점을 고려하십시오.부분단어 이름과 백틱을 원하지 않습니다. 때로는 arg 이름이 일반적인 단어(예: from)이고 함수 사용을 설명하는 맥락에서 사용할 때 백틱(자동)을 원합니다. 솔루션은 실제로 전혀 맞지 않았고 대신 vim일부 까다로운 매크로의 도움을 받아 반 수동으로 작업을 수행했습니다. :)

답변1

그건 어려운 일이에요. 당신이 이것을 가지고 있다고 가정 해 봅시다 file:

$ cat file
word
line with a word and words and wording wordy words.

어디:

  • 1행: 예약된 공간에 저장하고 참조해야 하는 검색 패턴입니다 `word`.
  • 2번째 줄: 전역 검색 및 바꾸기를 위한 줄입니다.

주문하다 sed:

sed -n '1h; 2{x;G;:l;s/^\([^\n]\+\)\n\(.*[^`]\)\1\([^`]\)/\1\n\2`\1`\3/;tl;p}' file

설명하다:

  • 1h;첫 번째 행을 예약된 공간에 저장합니다(이것이 우리가 검색하려는 대기입니다).
    • 숙박 공간에는 다음이 포함됩니다:word
  • 2{...}두 번째 행에 적용됩니다.
  • x;패턴 공간을 바꾸고 공간을 유지합니다.
  • G;예약된 공간을 패턴 공간에 추가합니다. 패턴 공간에는 다음이 있습니다.
word # I will call this line the "pattern line" from now on
line with a word and words and wording wordy words.
  • :l;l나중에 사용할 수 있도록 포인트라는 이름의 라벨을 설정하세요 .
  • s///위에서 언급한 패턴 공간에서 실제 검색/바꾸기를 수행합니다.
    • ^\([^\n]\+\)\n^줄의 시작 부분부터 [^\n](한 번 이상 \+) 줄 바꿈 문자까지 시작하여 줄 바꿈 문자가 아닌 모든 문자에 대해 "패턴 줄"을 검색합니다 \n. 이제 역참조에 저장되었습니다 \1. 여기에는 "패턴 라인"이 포함되어 있습니다.
    • (.*[^`]).*뒤에 문자(백틱 아님)가 오는 모든 문자를 검색합니다 [^`]. 이것은 에 저장됩니다 \2. \2이제 다음이 포함됩니다: 이후 line with a word and words and wording wordy마지막 발생까지 word...
    • \1는 다음 검색어(역참조 \1, word)이므로 "패턴라인"에 포함된 내용입니다.
    • ([^`])참조에 저장된 역따옴표가 아닌 다른 문자가 뒤에 옵니다 \3. 이 작업(및 위의 부분)을 수행하지 않으면 동일한 ->를 계속해서 참조하는 \2무한 루프에 빠지게 됩니다. 왜냐하면 항상 성공하고 다시 점프 하기 때문입니다 ( 아래 참조).word````word````s///tl;:ltl;
    • \1\n\2\1\3위의 모든 내용은 역참조로 대체됩니다. 두 번째는 \1우리가 인용해야 할 내용입니다(첫 번째 인용은 "패턴 라인"입니다).
  • tl;성공 하면 s///(무언가 교체) 이름이 지정된 태그로 점프하여 l검색하고 교체할 콘텐츠가 더 이상 없을 때까지 다시 시작합니다. 이는 해당 단어가 모두 대체/인용되는 경우입니다.
  • p;모든 작업이 완료되면 변경된 라인(패턴 공간)을 인쇄합니다.

산출:

$ sed -n '1h; 2{x;G;:l;s/^\([^\n]\+\)\n\(.*[^`]\)\1\([^`]\)/\1\n\2`\1`\3/;tl;p}' file
word
line with a `word` and `word`s and `word`ing `word`y `word`s.

답변2

조회 테이블은 어려울 수 있습니다.그리고 매우 비싸다- 패턴 공간의 양쪽 끝을 동시에 검색해야 하기 때문입니다. 그러나 구현하는 것은 적어도 다소 간단합니다. 무엇을 하든 한 번에 하나의 게임만 안정적으로 처리할 수 있다는 점을 고려해야 합니다. 따라서 g세계적인 결과를 얻으려는 희망을 포기하는 것이 좋습니다. 어쨌든, 그것은 상황을 혼란스럽게 할 뿐입니다. 컴파일된 표현식을 사용하지 않고 실제로 부작용을 다루고 있으며둘 다양쪽에서 시작하십시오.

printf  %s\\n some words to match \
        'and some words and some more words to match them against' |
sed  -ne'$!{H;d;}' -e'G;s/\(\n\).*/\1&\1/;tm' -e:m \
     -e 's/\(.\)\(.*\)\(.*\n\n.*\n\1\2\(\n\)\)/`\1\4\2`\3/;tm'

이것이 메인 루프입니다. 아직 청소를 하지 않았기 때문에 실제로는 작동하지 않지만 근본적인 문제를 해결합니다. 동일한 패턴 공간을 반복적으로 반복해야 하는데 일치 항목이 두 번 일치하지 않을 것이라고 어떻게 확신할 수 있습니까? 구분 기호로 끝내면 다시 일치 항목이 생기고 북엔드가 무한정 쌓이게 됩니다.

여기서 사용하는 솔루션은 게임을 깨뜨리는 것입니다. 물론 첫 번째 문자가 일치한 후에 줄바꿈을 삽입합니다. 물론 여전히 정리가 필요합니다. 그 일은 제가 처리하겠습니다. 그러나 조회 테이블에 다른 구성원의 하위 집합이 포함되어 있거나 단일 문자 집합을 사용하는 경우에는 여전히 작동하지 않습니다. 이를 수행하는 방법은 다양하며 더 좋은 방법도 있습니다. 필요한 경우 몇 가지 대안을 알려 드리겠습니다.

자세한 내용은 다음과 같습니다.

printf  %s\\n some words to match \
        'and some words and some more words to match them against' |
sed  -ne'$!{H;d;}' -e'G;s/\(\n\).*/\1&\1/;tm' -e:m \
     -e 's/\(.\)\(.*\)\(.*\n\n.*\n\1\2\(\n\)\)/`\1\4\2`\3/;tm' \
     -e  l

and `s\nome` `w\nords` and `s\nome` more `w\nords` `t\no` `m\natch` \
them against\n\n\nsome\nwords\nto\nmatch\n$

물론 정리도 쉽습니다.

printf  %s\\n some words to match \
        'and some words and some more words to match them against' |
sed  -ne'$!{H;d;}' -e'G;s/\(\n\).*/\1&\1/;tm' -e:m \
     -e 's/\(.\)\(.*\)\(.*\n\n.*\n\1\2\(\n\)\)/`\1\4\2`\3/;tm' \
     -e 's/\(`.\)\n/\1/g;P'

and `some` `words` and `some` more `words` `to` `match` them against

적어도 g전 세계적으로 이 작업을 수행할 수 있습니다.


이런 종류의 작업을 수행하기 위해 내가 선호하는 방법은 실제로 스크립트를 작성하는 것입니다.

printf  %s\\n some words to match \
        'and some words and some more words to match them against' |
{   sed -e"$(
        sed -ne'$w /dev/fd/3' -e$\q     \
             -e 's/[]\^$/.*[]/\\&/g'    \
             -e 's|..*|s/&/`\&`/g|p'
    )"  <&3
}   3<<""    3<>/dev/fd/3

and `some` `words` and `some` more `words` `to` `match` them against

sed명령 내 대체는 모든 입력 행에서 메타 문자를 이스케이프하도록 주의한 후 대체 문을 작성합니다(그러나 마지막 문자에는 포함될 수 있음) sed s///. 마지막 줄은 w문자 그대로 공유된 here-doc 파일 설명자에 기록되므로 sed외부에서 입력으로 읽을 수 있습니다. 내부적으로 sed다음과 같이 작동하는 스크립트를 인쇄합니다.

sed -e's/some/`&`/g'  \
    -e's/words/`&`/g' \
    -e's/to/`&`/g'    \
    -e's/match/`&`/g'

...그리고 마지막 줄을 다른 사람에게 넘겨서 sed작업하게 하세요.

관련 정보