아래와 같이 두 개의 파일이 있습니다. 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 0
0
-o
2.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
그러한 키 값이 없으면 배열의 값으로 설정합니다.key
0
산술 컨텍스트에서 초기화되지 않은 값이 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=1
mainfile
1
- 일단
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}")