다른 파일의 같은 줄에서 문자열 패턴의 여러 발생을 문자열과 일치하는 숫자로 바꾸는 awk 스크립트

Nov 26 2020

<> 안의 문자열을 검색하는 awk 스크립트가 필요합니다. 이전에 찾지 못한 문자열을 찾은 경우 인덱스 카운터의 현재 값 (처음에는 0)으로 바꾸고 카운터를 증가시켜야합니다. <> 안에서 이미 알고있는 문자열을 찾으면 문자열의 인덱스를 찾아서 인덱스로 대체해야합니다. 이는 여러 파일에서 수행되어야합니다. 즉, 프로그램 시작시에만 여러 파일에서 패턴을 검색 할 때 카운터가 재설정되지 않습니다. 예 : file_a.txt :

123abc<abc>xyz
efg
<b>ah
a<c>, <abc>
<c>b
(<abc>, <b>)

file_b.txt :

xyz(<c>, <b>)
xyz<b>xy<abc>z

되어야한다

file_a_new.txt :

123abc<0>xyz
efg
<1>ah
a<2>, <0>
<2>b
(<0>, <1>)

file_b_new.txt :

xyz(<2>, <1>)
xyz<1>xy<0>z

지금까지 얻은 것 :

awk 'match($0, /<[^>]+>/) { k = substr($0, RSTART, RLENGTH)
   if (!(k in freq))
      freq[k] = n++
   $0 = substr($0, 1, RSTART-1) freq[k] substr($0, RSTART+RLENGTH) } { print $0 > (FILENAME ".tmp")
}' files

그러나 이것은 한 줄에 하나의 <> 패턴 만 감지 할 수 있지만 한 줄에 여러 <> 패턴이있을 수 있습니다. 그렇다면 코드를 어떻게 변경해야합니까?

편집 : 파일은 편집 할 수 없으며 대신 새 파일을 만들어야합니다.

답변

3 anubhava Nov 26 2020 at 17:31

gnu-awk이 방법을 사용 RS하면 <key>문자열 로 사용 하는 것이 더 쉽습니다 .

awk -v RS='<[^>]+>' '{ ORS="" }  # init ORS to ""
RT {                                        # when RT is set
   if (!(RT in freq))                       # if RT is not in freq array
      freq[RT] = n++                        # save n in freq & increment n
   ORS="<" freq[RT] ">"                     # set ORS to < + n + >
}
{
   print $0 > ("/tmp/" FILENAME)
}' file_{a,b}.txt
1 EdMorton Nov 26 2020 at 17:24

awk 사용 :

$ cat tst.awk FNR == 1 { close(out) out = FILENAME ".tmp" } { head = "" tail = $0
    while ( match(tail,/<[^>]+>/) ) {
        tgt = substr(tail,RSTART+1,RLENGTH-2)
        if ( !(tgt in map) ) {
            map[tgt] = cnt++
        }
        head = head substr(tail,1,RSTART) map[tgt]
        tail = substr(tail,RSTART+RLENGTH-1)
    }
    print head tail > out
}

$ head file_*.tmp
==> file_a.txt.tmp <==
123abc<0>xyz
efg
<1>ah
a<2>, <0>
<2>b
(<0>, <1>)

==> file_b.txt.tmp <==
xyz(<2>, <1>)
xyz<1>xy<0>z