중복 값을 기준으로 목록 병합

중복 값을 기준으로 목록 병합

저는 다음과 같이 데이터를 정리했습니다.

a
a f
b
c
c e
d
f z

기본적으로 이 줄은 모두 동일한 항목에 대한 별칭 목록이므로 병합해야 합니다. 이것은 단순화되었습니다. 실제 상황에서 중요한 경우 이동된 파일 경로를 다루고 있으며 어떤 파일 경로가 본질적으로 동일한지 알아야 합니다. 입력에는 초기 파일에 대한 열 1개와 파일 이름 바꾸기에 대한 열 2개가 있습니다. 다음과 같은 출력을 찾으십시오.

a f z
b
c e
d

이것은 일반적인 Linux 시스템의 bash 스크립트용이므로 대부분의 표준 도구가 가능합니다. 지금까지 이 주제를 다루는 다른 질문에서 몇 가지 awk 스크립트를 시도했지만 좋은 결과를 찾지 못했습니다.

답변1

Awk해결책:

awk '{ 
         if (NF == 2) {
             if ($1 in r) { 
                 a[r[$1]] = a[r[$1]] OFS $2; next 
             } 
             a[$1] = $2; r[$2] = $1; 
         } 
         else a[$1]; 
     }
     END{ for (i in a) print i, a[i]  }' file
  • NF == 2- 2개의 필드가 있는 레코드를 나타내는 조건( NF- 총 필드 수)
  • a- 원래 파일 이름과 이름이 바뀐 버전 사이의 합계 또는 관계와 같은 "독립형" 파일 이름(이름이 바뀌지 않은)을 포함하는 배열( b예:)da -> f
  • r- 역관계 "이름이 변경된 파일 이름" -> "초기 파일 이름"을 포함하는 배열(예 f -> a: )

산출:

a f z
b 
c e
d 

일부 파일 이름을 여러 번 바꿀 수 있는 경우 다음 확장 솔루션을 사용하십시오.

awk '{ 
         if (NF == 2) {
             if ($1 in r) { 
                 a[r[$1]] = a[r[$1]] OFS $2; r[$2] = r[$1];
             } 
             else { a[$1] = $2; r[$2] = $1 } 
         } 
         else a[$1]; 
     }
     END{ for (i in a) print i, a[i]  }' file

답변2

gawk '
{
    arr[cnt][0] = $1    
    arr[cnt++][1] = $2  
}
END {
    for(i = 0; i < cnt; i++) {
        if(!arr[i][0]) continue

        next_name = arr[i][0]

        for(j = i; j < cnt; j++) {
            if(arr[j][0] != next_name) continue

            if(arr[j][1]) {
                next_name = arr[j][1]
                delete arr[j]
            }
            printf "%s ", next_name

        }
        print ""
    }
}' cnt=0 input.txt

입력하다(테스트가 복잡함)

u
a
a f
b
c
c e
d
c
f g
g a
a i
i j
a
a z
z w

산출

u 
a f g a i j 
b 
c e 
d 
c 
a z w 

관련 정보