두 파일을 열별로 병합하고 항목이 누락되면 0을 추가합니다.

두 파일을 열별로 병합하고 항목이 누락되면 0을 추가합니다.

아래와 같이 두 개의 파일이 있습니다. File 2에 누락된 항목이 있는 곳에 0을 추가하여 File 1과 File 2의 두 번째 열에 있는 모든 항목을 포함하는 마스터 파일을 만드는 방법을 찾으려고 합니다. 이 모든 파일은 탭으로 구분됩니다. 명령을 시도했지만 join작동하지 못했습니다.

  • 의 예File1
    orange
    banana
    berry
    cherry
    strawberry
    
  • File2:
    orange   1   
    banana   2   
    cherry   1   
    
  • 원하는 출력
    Output    Value
    orange     1
    banana     2
    berry      0
    cherry     1
    strawberry 0
    

내가 시도한 것:

join File1 File2 |less

답변1

$ join -a 1 -e 0 -o 0,2.2 <(sort File1) <(sort File2)
banana 2
berry 0
cherry 1
orange 1
strawberry 0

join파일 간의 관계형 JOIN 작업을 수행 하는 데 사용됩니다 . 이를 위해서는 두 파일을 모두 정렬해야 하며, 이것이 각 프로세스 교체 시 파일을 정렬하는 이유입니다(원하는 경우 데이터를 미리 정렬할 수 있음). 이 명령은 첫 번째 입력 파일( )의 모든 행을 나열하고 -a 1누락된 필드를 ( )로 바꿉니다. 출력의 필드는 연결된 필드(기본적으로 각 파일의 첫 번째 필드이며 옵션에 대한 인수에 기록됨)와 두 번째 파일의 두 번째 필드( )입니다.0-e 00-o2.2

장점: 빠르고(특히 데이터가 이미 정렬된 경우) 메모리 효율적입니다.
단점: 데이터를 재정렬합니다.


원래 순서를 유지하려면 다음을 File1사용할 수 있습니다 awk.

$ awk 'NR == FNR { key[$1] = $2; next } { $2 = ($1 in key) ? key[$1] : 0 }; 1' File2 File1
orange 1
banana 2
berry 0
cherry 1
strawberry 0

File2첫 번째 열을 연관 배열의 키로 읽고 key두 번째 열을 연관된 값으로 읽습니다 .

읽을 때 File1( 더 이상 같지 않음) NR첫 번째 열에 해당하는 키가 있으면 두 번째 열을 배열의 값으로 설정하고,FNR 그러한 키 값이 없으면 배열의 값으로 설정합니다.key0

산술 컨텍스트에서 초기화되지 않은 값이 0이라는 사실을 악용하여 코드를 약간 단축할 수 있습니다.

$ awk 'NR == FNR { key[$1] = $2; next } { $2 = 0+key[$1] }; 1' File2 File1
orange 1
banana 2
berry 0
cherry 1
strawberry 0

장점: 출력이 정렬됩니다 File1.
단점: 데이터가 File2메모리에 저장됩니다(많은 행을 읽을 때만 중요함).

답변2

이 작업을 수행하는 명령은 모르지만 다음과 같이 스크립트로 작성할 수 있습니다.

while IFS='' read -r l1; do
  grep "^${l1}" File2 || echo -e "${l1}\t0"
done < <(cat File1)

답변3

사용할 수 있지만 awk버퍼링이 필요합니다 File2.거대한일반적으로 그럴 가능성은 낮지만 파일이 한계에 도달할 수도 있습니다.

awk 'BEGIN{FS=OFS="\t"}
     !mainfile{val[$1]=$2;next}
     {if ($1 in val) {$2=val[$1]} else {$2=0}} 1' File2 mainfile=1 File1

작동 방식은 다음과 같습니다.

  • 처리하기 전에 입력 및 출력 필드 구분 기호를 TAB으로 설정합니다.
  • 초기화되지 않은 변수로 표시된 첫 번째 입력 파일( File2이 경우) 을 처리할 때 mainfile각 "과일"의 "값"을 연관 배열에 기록하기만 하면 됩니다 val. 그 후 바로 다음 입력 라인으로 처리를 건너뜁니다(그리고 처리 시에만 적용해야 하는 부분은 건너뜁니다 File1).
  • 로 설정할 awk명령문 은 .mainfile=1mainfile1
  • 일단 mainfile설정되면 첫 번째 규칙은 무시되고 두 번째 규칙만 처리됩니다. 여기서는 열 1의 항목에 매핑된 "값"이 있는지 확인합니다. 그렇다면 해당 값을 열 2에 사용하고, 그렇지 않으면 열 2를 로 설정합니다 0.
  • 1규칙 블록 외부에 있는 것처럼 보이는 내용은 awk수정 사항을 포함하여 현재 줄을 인쇄하도록 지시합니다.

답변4

Python으로 빠르게 구현할 수 있는 것 같습니다.

#!/usr/bin/env python3
"""
Overly grande solution to the problem posed in the question.
"""
import sys

# Check whether the user specified two arguments to the script
if not len(sys.argv) == 3:
  sys.stderr.write(f"Usage: {sys.argv[0]} File1 File2")
  sys.exit(-1)

# Empty dictionary
dictionary = {}

# Fill the dictionary with zero-entries from the first file
with open(sys.argv[1]) as file:
  for line in file:
   dictionary[line.strip()] = 0

# Replace the zero entries when found in second file
with open(sys.argv[2]) as file:
  for line in file:
    entry, value = line.split()
    dictionary[entry] = int(value)

# print the result table
print("Output\tValue")
for key, value in dictionary.items():
  # We're using the format string syntax to give the count
  # field a constant length of 8, so that things are nicely
  # right-aligned.
  print(f"{key}\t{value:8}")

관련 정보