쉘 스크립트를 사용하여 파일에서 중복된 텍스트 블록 찾기

쉘 스크립트를 사용하여 파일에서 중복된 텍스트 블록 찾기

다음 줄을 포함하는 텍스트 파일이 있다고 가정합니다.

abcd/efgh/a.jar
{
abcd/efgh/a.class
cdef/ghij/b.class
klmn/opqr/c.class
}
lkmn/opqr/b.zip
{
abcd/efgh/a.class
cdef/ghij/b.class
}
abcd/efgh/a.jar
{
cdef/ghij/b.class
}

이제 첫 번째 경우 abcd/efgh/a.jar에는 중괄호 안에 abcd/efgh/a.class, cdef/ghij/b.class 및 klmn/opqr/c.class가 있습니다. 1개의 텍스트 블록으로 생각하세요. 이제 다음 abcd/efgh/a.jar에는 다시 중괄호 안에 cdef/ghij/b.class가 있습니다. 이 텍스트 섹션/블록을 제거하고 싶습니다. 따라서 최종 출력은 다음과 같아야 합니다.

abcd/efgh/a.jar
{
abcd/efgh/a.class
cdef/ghij/b.class
klmn/opqr/c.class
}
lkmn/opqr/b.zip
{
abcd/efgh/a.class
cdef/ghij/b.class
}

어떤 도움이라도 대단히 감사하겠습니다 :)

답변1

사용

for i in `awk '/}/ {if (NR!=1) print "";next} \
                {printf "%s ",$0,"}"}END{print ""}' yt.txt \
        |awk '{print $1}'|sort|uniq \
    `; \
    do \
        awk '/}/ {if (NR!=1) print "";next} \
            {printf "%s ",$0,"}"}END{printf ""} \
            ' yt.txt \
         |grep "$i"|sed 's/ /\n/g'|grep -v "$i"|sort|uniq \
            |awk -v var="$i" ' NR==1 {printf var} {print $0} END {print "}"}'  \
    ;done \

아래 한 줄의 동일한 명령(복사 목적)

for i in `awk '/}/ {if (NR!=1) print "";next} {printf "%s ",$0,"}"}END{print ""}' yt.txt|awk '{print $1}'|sort|uniq` ; do awk '/}/ {if (NR!=1) print "";next} {printf "%s ",$0,"}"}END{printf ""}' yt.txt|grep "$i"|sed 's/ /\n/g'|grep -v "$i"|sort|uniq|awk -v var="$i" ' NR==1 {printf var} {print $0} END {print "}"}' ;done

설명하다:

이 섹션은 블록의 고유 제목( , ) for을 반환 하고 이를 블록에 전달합니다. 이 섹션에는 먼저 중복 항목을 포함하여 각 제목에 대한 모든 행이 표시됩니다 . 그런 다음 헤더를 제외하고 해당 헤더 블록 아래에 남아 있는 모든 행을 병합한 다음 첫 번째 행에 헤더를 추가합니다. 그리고 마지막에 하드코딩했습니다.abcd/efgh/a.jarlkmn/opqr/b.zipdodogrep}

bash-4.2$ cat yt.txt
abcd/efgh/a.jar
{
abcd/efgh/a.class
cdef/ghij/b.class
klmn/opqr/c.class
}
lkmn/opqr/b.zip
{
abcd/efgh/a.class
cdef/ghij/b.class
}
abcd/efgh/a.jar
{
cdef/ghij/b.class
d.class
}



bash-4.2$ for i in `awk '/}/ {if (NR!=1) print "";next} {printf "%s ",$0,"}"} \
> END{print ""}' yt.txt |awk '{print $1}'|sort|uniq` \
> ; do awk '/}/ {if (NR!=1) print "";next} {printf "%s ",$0,"}"}END{printf ""}' yt.txt \
>  |grep "$i"|sed 's/ /\n/g'|grep -v "$i"|sort|uniq \
> |awk -v var="$i" ' NR==1 {printf var} {print $0} END {print "}"}'\
> ;done
abcd/efgh/a.jar
{
abcd/efgh/a.class
cdef/ghij/b.class
d.class
klmn/opqr/c.class
}
lkmn/opqr/b.zip
{
abcd/efgh/a.class
cdef/ghij/b.class
}

답변2

forawkand sort및 and 가 포함된 uniq루프를 사용하는 솔루션을 본 후 6개 도구 대신 하나의 도구를 사용하여 솔루션을 시도했습니다.grepsed

sed ':a
  N;$!ba
  y/\n_/_\n/;s/^/_/
  :b
  s/\(_[^_]*_{\)\([^}]*\)\(_[^_}]*\)\(_[^}]*\)\(_}.*\)\1\([^}]*\)\3_/\1\2\3\4\5\1\6_/;tb
  :c
  s/\(_[^_]*_{\)\([^}]*\)_}\(.*\)\1\([^}]*\)_}/\1\2\4_}\3/;tc
  s/^_//
  y/\n_/_\n/' yourfile

그 일을 할 수는 있지만 정규식 작성이 읽는 것보다 쉽다는 점을 인정해야 합니다... (-;

답변3

perl -alF'/\n[}{]\n/' -0777ne '
   for ( 0 .. $#F/2 ) {
      my $i = 2*$_;
      my($k,$v) = @F[$i,$i+1];
      if ( exists $h{$k} ) {
         $h{$k} .= join $\, grep { ! exists $seen{$k,$_} } split $\, $v;
      } else {
         push @k, $k;
         $seen{$k,$_}++ for split $\, $h{$k} = $v;
      }
   }
   print "$_\n{\n$h{$_}\n}" for @k;
' yourfile

결과

abcd/efgh/a.jar
{
abcd/efgh/a.class
cdef/ghij/b.class
klmn/opqr/c.class
}
lkmn/opqr/b.zip
{
abcd/efgh/a.class
cdef/ghij/b.class
}

피복재

입력 파일은 다이제스트된 다음 옵션에 언급된 필드 구분 기호에 따라 필드로 분할됩니다 -F. 우리는 배열에서 짝수의 요소를 얻게 될 것입니다 @F. 그런 다음 짝수는 %h대응하는 동안 해시 키 역할을 합니다. 값은 다음 홀수부터 가져옵니다.

%h해시는 레코드 구분 기호($\ = \n)에서 홀수 요소를 분할하여 채워집니다. 동시에 @k해시 요소를 발견된 순서대로 검색할 수 있도록 키를 배열에 넣습니다.

그동안 아직 본 적이 없는 이상한 요소들만 사용하고 있습니다.

관련 정보