목록을 기반으로 sed 대체(s///g)를 수행하는 방법은 무엇입니까? 여러 단어를 해당하는 다른 단어로 바꿔야 합니다.

목록을 기반으로 sed 대체(s///g)를 수행하는 방법은 무엇입니까? 여러 단어를 해당하는 다른 단어로 바꿔야 합니다.

sed이전에 누구도 이 질문을 한 적이 없는 것 같아서 제가 이런 일을 할 수 있을지 모르겠습니다 .

한 문장에 많은 숫자가 있고 이를 단어로 확장해야 한다고 가정해 보겠습니다. 실제적인 예는 일반적인 논문에서 번호가 매겨진 인용을 MLA 형식으로 바꾸는 것입니다.

essay.txt:

Sentence 1 [1]. sentence two [1][2]. Sentence three[1][3].

Key.txt(탭으로 구분된 파일입니다):

1   source-one
2   source-two
3   source-three
...etc

예상되는 Result.txt:

Sentence 1 [source-one]. sentence two [source-one][source-two]. Sentence three[source-one][source-three]

다음은 의사코드 시도입니다. 그러나 이에 대해 충분히 알지 못하거나 sed올바르게 tr수행할 수 없습니다.

 cat essay.txt | sed s/$(awk {print $1} key.txt)/$(awk {print $2} key.txt)/g

추신: 메모장++에 여러 용어를 사용하여 일괄 찾기 및 바꾸기를 위한 트릭이 있다면 좋을 것입니다. 실제로 찾기 및 바꾸기는 한 번에 한 용어에 대해서만 작동하는 것처럼 보이지만 동시에 여러 용어에 대해 집합적으로 작동할 수 있는 방법이 필요합니다.

답변1

다음을 사용해야 합니다 perl.

$ perl -ne '
  ++$nr;
  if ($nr == $.) {
    @w = split;
    $k{$w[0]} = $w[1];
  }
  else {
    for $i (keys %k) {
      s/(\[)$i(\])/$1.$k{$i}.$2/ge
    }
    print;
  }
  close ARGV if eof;
' key.txt essay.txt
Sentence 1 [source-one]. sentence two [source-one][source-two]. Sentence three[source-one][source-three]

답변2

awkperl여기서와 동일한 작업을 효과적으로 수행할 수 있습니다.더 간단하다, GNU 이외의 구현에서는 텍스트 파일을 불필요하게 분할(대형?)하여 약간의 CPU 시간을 낭비할 수 있지만:

awk 'NR==FNR{a["\\["$1"\\]"]="["$2"]";next} {for(k in a) gsub(k,a[k]);print}' key.txt essay.txt

당신이 물어본 이후로설명하다:

  • awk패턴-액션 쌍으로 구성된 "스크립트"를 취한 다음 한 번에 하나의 "레코드"씩 하나 이상의 파일(또는 표준 입력)을 읽으면 각 레코드는 기본적으로 한 줄이고 각 레코드에 대해 필드로 분할됩니다. 기본적으로 공백(탭 포함)을 사용하고 각 패턴을 차례로 테스트하여(별도의 지시가 없는 한)(보통 현재 레코드 및/또는 해당 필드를 확인) 일치하는지(보통 스크립트를 적용하기 위해 작업을 수행) 작업을 수행합니다. 설명된 기록 및/또는 필드와 함께). 여기서는 두 개의 파일을 지정했으므로 key.txt essay.txt두 파일을 해당 순서대로 한 줄씩 읽습니다. 스크립트할 수 있는명령줄이 아닌 파일에 있지만 여기서는 그렇게 하지 않기로 결정했습니다.

  • 첫 번째 패턴은 처리 중인 레코드 번호를 나타내는 내장 변수입니다. NR==FNR는 현재 입력 파일의 레코드 번호입니다. 첫 번째 파일( )에서는 동일하지만 두 번째 파일(및 기타 파일)에서는 동일하지 않습니다.NRFNRkey.txt

  • 첫 번째 작업은 입니다 {a["\\["$1"\\]"]="["$2"]";next}. awk"연관" 또는 "해시" 배열이 있습니다. arrayname[subexpr]여기서 는 subexpr배열의 요소를 읽거나 설정하는 문자열 값 표현식입니다. $number예를 들어 $1 $2필드를 참조하고 $0전체 기록을 참조합니다. 위의 내용에 따르면 이 작업은 key.txt파일의 마지막 줄인 $1is 3$2is 와 같은 의 줄에서만 수행되며 index 및 content source-three가 포함된 배열 항목을 저장합니다 . 이 값을 선택한 이유는 아래를 참조하세요. and 는 이스케이프 를 사용하는 문자열 리터럴이고 실제 값은 입니다. 반면 while 은 바로 그 것이며 사이에 연산자가 없는 문자열 피연산자가 연결됩니다. 이 작업을 마지막으로 수행한다는 것은 이 레코드에 대한 나머지 스크립트를 건너뛰고 루프의 맨 위로 돌아가서 다음 레코드를 시작하는 것을 의미합니다.\[3\][source-three]"\\[""\\]"\[\]"[" "]"[ ]next

  • 두 번째 패턴은 비어 있으므로 두 번째 파일의 모든 줄과 일치하고 작업을 수행합니다 {for(k in a) gsub(k,a[k]);print}. 이 for(k in a)구성은 Bourne 유형 쉘이 에서 수행하는 것과 매우 유사한 루프를 생성합니다 for i in this that other; do something with $i; done. 단, 여기서 값은 다음 k과 같습니다.아래 첨자a그러한 각 값에 대해 gsub(전역 교체) 주어진 정규 표현식의 모든 항목을 찾아 주어진 문자열로 바꿉니다. 배열(위)에서 아래 첨자와 내용을 선택했습니다. 예를 들어 다음과 같습니다 \[3\]. 텍스트 문자열과 일치하는 정규 표현식 [3]이며, [source-three]해당 일치 항목마다 바꾸려는 텍스트 문자열입니다. 기본적으로 gsub작업은 현재 레코드에서 수행됩니다 $0. 그 안에 있는 모든 값을 대체한 후에는 기본적으로 현재 출력이 a실행되고 필요한 모든 대체가 완료됩니다.print$0

참고: Linux에서는 일반적이지만 보편적이지 않은 GNU awk(gawk)에는 수행 중인 패턴이나 작업에 필드 값이 필요한 항목이 없는 경우 실제로 필드 분할을 수행하지 않는 최적화 기능이 있습니다. 다른 구현에서는 약간의 CPU 시간이 낭비될 수 있으며 cuonglm의 perl접근 방식은 이를 방지하지만 파일이 매우 크지 않으면 이 사실을 알아차리지 못할 수도 있습니다.

답변3

bash$ sed -f  <( sed -rn 's#([0-9]+)\s+(.*)#s/\\[\1]/[\2]/g#p' key.txt ) essay.txt

Sentence 1 [source-one]. sentence two [source-one][source-two]. Sentence three[source-one][source-three].

답변4

루프 내에서 내부 sed 대체를 사용하여 이를 달성할 수 있습니다.

$ cp essay.txt Result.txt
$ while read n k; do sed -i "s/\[$n\]/\[$k\]/g" Result.txt; done < key.txt
$ cat Result.txt 
Sentence 1 [source-one]. sentence two [source-one][source-two]. Sentence three[source-one][source-three].

관련 정보