잠재적으로 불완전한 키를 기반으로 파일 병합

잠재적으로 불완전한 키를 기반으로 파일 병합

다음과 같은 두 파일을 병합하고 싶습니다두 열의 일치를 기반으로 두 파일을 병합하는 방법은 무엇입니까?그러나 하나의 파일에 모든 결과가 포함되지 않을 수도 있습니다. 예를 들어

파일 1

1 dog
2 cat
3 fox
4 cow

파일 2

1 woof
2 meow
4 mooh

원하는 출력

1 dog woof
2 cat meow
3 fox
4 cow mooh

답변1

배열의 배열을 처리하려면 GNU awk를 사용하십시오.

$ awk '{a[$1][(NR>FNR)]=$2} END{for (i in a) print i, a[i][0], a[i][1]}' file{1,2}
1 dog woof
2 cat meow
3 fox
4 cow mooh

또는 awk를 사용하십시오.

$ awk '{keys[$1]; a[$1,(NR>FNR)]=$2} END{for (i in keys) print i, a[i,0], a[i,1]}' file{1,2}
1 dog woof
2 cat meow
3 fox
4 cow mooh

위의 출력은 첫 번째 필드의 숫자 오름차순이지만 이는 단지 행운/우연일 뿐입니다. 출력 행의 순서는 실제로 "in" 연산자에서 제공하는 "무작위"(일반적으로 해시 순서)입니다. 관심이 있다면 출력을 파이프로 연결하십시오 sort -k1,1n(또는 PROCINFO["sorted_in"]="@ind_num_asc"GNU awk의 END 섹션 시작 부분에 설정하십시오).

이 솔루션과 솔루션의 중요한 차이점은 다음 join과 같습니다.

  1. 이는 입력이 정렬되지 않고 join키 필드에서 입력을 정렬해야 하는 경우에도 작동합니다.
  2. file2에 file1에 없는 키가 있는 행이 있는 경우(또는 그 반대의 경우) add -a2to join명령과 달리 해당 고유 행이 어떤 파일에서 왔는지 알 수 있는 방식으로 이를 표시합니다.

다음은 테스트를 위한 좀 더 포괄적인 입력/출력 예시입니다.

$ head file{1,2}
==> file1 <==
1 dog
2 cat
4 cow
5 bear

==> file2 <==
1 woof
2 meow
3 growl
4 mooh

그런 다음 위의 awk 스크립트를 실행하여 동일한 출력을 얻을 수 있습니다.

$ awk '{a[$1][(NR>FNR)]=$2} END{for (i in a) print i, a[i][0], a[i][1]}' file{1,2}
1 dog woof
2 cat meow
3  growl
4 cow mooh
5 bear

그리고 3 growl앞에 추가 공백이 있으므로 growl이것이 file2의 유일한 줄임을 알 수 있습니다 join. 대신 다음을 사용하십시오.

$ join -a1 -a2 file1 file2
1 dog woof
2 cat meow
3 growl
4 cow mooh
5 bear

file1의 고유 행(예: 5 bear)과 file2의 고유 행(예: 3 growl)을 구별할 수 없습니다.

답변2

file1과 file2가 모두 정렬되어 있다고 가정하면 join기본적으로 두 파일에 키가 있는 줄만 연결됩니다. 따라서 귀하의 경우 file2에는 키가 "3"인 행이 없으므로 해당 행은 결합되지 않습니다. 그러나 이 동작을 변경할 수 있습니다.

다음 매뉴얼 페이지에서 join:

   -a FILENUM
          also print unpairable lines from file FILENUM, where FILENUM is 1 or 2, corresponding to FILE1 or FILE2

따라서 -a1이 플래그를 join명령에 추가하면 file2에 일치하는 키가 없는 file1의 모든 줄도 인쇄됩니다.

# join -a1 file1 file2
1 dog woof
2 cat meow
3 fox
4 cow mooh

이것은 file2에서 페어링할 수 없는 줄을 처리하지 않으므로 file2에 다음과 같은 다른 줄이 있습니다.

5 quack

이 줄은 인쇄되지 않습니다. file2의 행을 인쇄하는 -a2명령에 플래그를 추가 할 수도 있지만 join행이 file1에서 왔는지 아니면 file2에서 왔는지 알 수 없기 때문에 혼란만 가중됩니다.

답변3

키와 값을 연관 배열에 넣고 file3에 인쇄합니다.

declare -A arr

while read key value
do
    if [ -z ${arr[$key]} ]; then
        arr[$key]=$value
    else
        arr[$key]="${arr[$key]} $value"
    fi
done < <(cat file1 file2)

echo -n > file3

for key in "${!arr[@]}"
do
    echo "$key ${arr[$key]}" >> file3
done

관련 정보