다른 파일의 두 열을 비교하고 일치하면 인쇄


16

Solaris 10을 사용하고 있으므로 -f와 관련된 grep 옵션이 작동하지 않습니다.

파이프로 구분 된 두 개의 파일이 있습니다.

file1 :

abc|123|BNY|apple|
cab|234|cyx|orange|
def|kumar|pki|bird|

파일 2 :

abc|123|
kumar|pki|
cab|234

일치하는 file1 행을 인쇄하는 경우 file2의 처음 두 열을 file1과 비교합니다 (처음 두 열에서 file1의 전체 내용을 검색). 그런 다음 파일 2의 두 번째 행을 검색하십시오.

예상 출력 :

abc|123|BNY|apple|
cab|234|cyx|orange|

내가 가지고있는 파일은 약 40 만 줄을 포함하여 크기가 커서 실행을 빠르게하고 싶습니다.


예제에서 선행 공백을 제거했습니다. 원한다면 편집을 롤백하십시오. 공백은 중요하므로 실제 파일에 공백이 있으면 있어야합니다.
terdon

grep아래 의 GNU 버전을 사용해보십시오 /usr/sfw/bin/ggrep. stackoverflow.com/questions/15259882/…
slm

답변:


21

이것은 awk을 위해 설계된 것입니다.

$ awk -F'|' 'NR==FNR{c[$1$2]++;next};c[$1$2] > 0' file2 file1
abc|123|BNY|apple|
cab|234|cyx|orange|

설명

  • -F'|': 필드 구분 기호를로 설정합니다 |.
  • NR==FNR: NR은 현재 입력 행 번호이고 FNR은 현재 파일의 행 번호입니다. 두 번째 파일은 첫 번째 파일을 읽는 동안에 만 동일합니다.
  • c[$1$2]++; next: 이것이 첫 번째 파일 인 경우 첫 번째 두 필드를 c배열 에 저장하십시오 . 그런 다음 첫 번째 파일에만 적용되도록 다음 줄로 건너 뜁니다.

  • c[$1$2]>0: else 블록은 이것이 두 번째 파일 인 경우에만 실행되므로이 ​​파일의 필드 1과 2가 이미 표시되어 c[$1$2]>0있는지 ( ) 확인한 다음 해당 필드가 있으면 행을 인쇄합니다. 에서 awk, 기본 동작은 경우 있도록 라인을 인쇄하는 것입니다 c[$1$2]>0사실, 라인이 인쇄됩니다.


또는 Perl 태그로 설정 했으므로 :

perl -e 'open(A, "file2"); while(<A>){/.+?\|[^|]+/ && $k{$&}++};
         while(<>){/.+?\|[^|]+/ && do{print if defined($k{$&})}}' file1

설명

첫 번째 줄이 열리고 file2두 번째 |( .+?\|[^|]+) 까지 모든 것을 읽고 해시에 저장합니다 ( $&마지막 일치 연산자의 결과 임) %k.

두 번째 줄은 file1을 처리하고 동일한 정규식을 사용하여 첫 번째 두 열을 추출하고 해당 열이 %k해시에 정의되어 있으면 해당 줄을 인쇄합니다 .


위의 두 가지 접근 방식은 모두 file2의 두 번째 열을 메모리에 보관해야합니다. 수십만 줄만 있으면 문제가되지 않지만 그럴 경우 다음과 같은 작업을 수행 할 수 있습니다

cut -d'|' -f 1,2 file2 | while read pat; do grep "^$pat" file1; done

그러나 그것은 느려질 것입니다.


그러나 이것이 모든 (첫 번째 두 열) file2메모리에 로드되지 않습니까?
Joseph R.

@terdon : awk -F'|' 'NR==FNR{c[$1$2]++;next};c[$1$2] > 0'더 짧은 버전입니다.
cuonglm

작동하지 않습니다 ..
user68365

@ user68365 : file2중복 행이 있습니까?
cuonglm

아니요 중복 행이 없습니다
user68365

1

나는 생각한다

grep -Ff file2 file1

당신이 찾고있는 것입니다. 효율적이어야하지만 원하는만큼 정확할지는 확실하지 않습니다. 경우 abc|123(예)는 한 행에서 발견되는 file1다른 열에서, 그 선은 물론 인쇄한다. 이런 일이 발생하지 않을 것이라고 보장 할 수 있으면 위의 행이 작동합니다.


abc | 123이 파일의 어딘가에 존재할 수 있으므로 Grep이면 충분하지 않습니다. 또한 나는 solaris 10을 사용하고 있으며 그 grep 옵션도 사용할 수 없습니다.
user68365

2
@ user68365 귀하의 질문 에이 모든 것을 명확히하십시오. OS를 알려주고 처음 두 열만 일치 시키도록 지정해야합니다.
terdon

1

SQL과 같은 방식으로 문제를 생각하려면 ' q ' 라는 도구를 사용해보십시오 .

$ q -d '|' "select f1.* from file1 f1 join file2 f2 on (f1.c1 = f2.c1 and f1.c2 = f2.c2)"

SQL 쿼리에 익숙하면 더 명확하고 이해하기 쉽습니다.


지금까지 가장 암호화 된 솔루션 중 하나에 감사드립니다. 그것이 내가 원하는 것입니다. 그러나이 "q 도구"를
Rolf

매우 유용한 도구입니다.
ghilesZ

0
$  sed 's/^/\^/' 2.txt > temp.txt ; grep 1.txt -f temp.txt
abc|123|BNY|apple|
cab|234|cyx|orange|

1
질문에서 편집하고 언급했듯이 grep -f 옵션이 내 시스템에서 작동하지 않습니다.
user68365

솔라리스 10은 GNU 코어 - 유틸에서 / usr / sfw / bin을 가지고 사용은 / usr / SFW / 빈 / SED와는 / usr / SFW / 빈 / 그렙
mr_tron
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.