특정 필드의 Grep 파일

특정 필드의 Grep 파일

두 개의 파일이 있습니다.

파일 1:

Locus_1
Locus_2
Locus_3

파일 2:

3  3  Locus_1  Locus_40  etc_849    
3  2  Locus_2  Locus_94  *    
2  2  Locus_6  Locus_1  *    
2  3  Locus_3,Locus_4  Locus_50  *    
3  3  Locus_9  Locus_3  etc_667

grep -F첫 번째 파일에 대한 파일을 만들고 싶습니다.오직예를 들어 두 번째 파일의 세 번째 열(원래 File2필드는 탭으로 구분됨)에서 출력은 다음과 같아야 합니다.

산출:

3  3  Locus_1  Locus_40  etc_849    
3  2  Locus_2  Locus_94  *    
2  3  Locus_3,Locus_4  Locus_50  *

어떻게 해야 합니까?

편집 혼란: 아니요, 쉼표는 오류가 아닙니다. 한 열에 여러 개의 Locus_*를 가질 수 있습니다. 두 번째 Locus_*(쉼표 뒤의 것)가 행 중 하나와 일치하면 File1그것도 검색되기를 원합니다!

답변1

필요하지 않은 경우 grep간단한 해결책은 다음을 사용하는 것입니다 join.

$ join -1 1 -2 3 <(sort file1) <(sort -k3 file2)
Locus_1 3 3 Locus_40 etc_849
Locus_2 3 2 Locus_94 *
Locus_3 2 3 Locus_4 Locus_50 *

설명하다:

  • join -1 1 -2 3: 첫 번째 파일의 첫 번째(유일한) 필드와 두 번째 파일의 세 번째 필드를 사용하여 두 파일을 연결합니다. 동일할 때 인쇄됩니다.
  • <(sort file1): join정렬된 입력이 필요합니다.
  • <(sort -k3 file2):입력은 조인 필드(여기서는 세 번째 필드)에서 정렬되어야 합니다.

답변2

솔루션 조정https://stackoverflow.com/a/9937241/1673337(g)awk를 사용하여 다음을 얻을 수 있습니다.

awk 'NR==FNR{a[$0]=1;next} {for(i in a){if($3~i){print;break}}}' File1 File2

주어진 출력을 제공합니다.

세 번째 열에서만 일치하도록 grep하는 정규식을 만들 수 있지만 이 시점에서는 awk를 사용하는 것이 더 이해하기 쉽다는 것을 알았습니다.

이 섹션은 세 번째 열이 File1(배열 a에 저장됨)의 행과 일치하는 경우에만 인쇄를 담당합니다 if($3~i){print;break}. 나머지 설명은 링크된 게시물을 참조하세요.

이렇게 하면 File1의 전체 내용을 메모리로 읽게 되지만 이는 파일이 매우 큰 경우에만 문제가 됩니다. 이 경우 비교의 곱셈 특성으로 인해 어쨌든 최적화해야 합니다.

답변3

사용grep -F옵션 검색단어어딘가에현재 줄에. 정의에 따르면,단어이는 정규식을 사용하여 필드 3 내로만 검색 범위를 좁힐 수 없음을 의미합니다.(탭으로 구분됨).

그러나 다음을 사용할 수 있습니다.grep -f패턴 입력 읽기파일 1- 하지만 정규식 목록으로 수정해야 합니다. 다음은 bash 프로세스 대체 및 sed를 사용하여 표준 정규식 목록을 생성하는 한 가지 방법입니다.grep -f처리할 수 있습니다.

grep을 사용하여기본 정규식:

  grep -f <(sed 's/.*/^\\([^\t]\\+\t\\)\\{2\\}\\([^\t]\\+,\\)*&[,\t]/'  file1) file2

grep을 사용한 기본 정규식의 경우,file1다음으로 동적으로 변환됩니다.

^\([^   ]\+ \)\{2\}\([^ ]\+,\)*Locus_1[,    ]
^\([^   ]\+ \)\{2\}\([^ ]\+,\)*Locus_2[,    ]
^\([^   ]\+ \)\{2\}\([^ ]\+,\)*Locus_3[,    ]

또는: 사용grep -E그리고확장 정규식대부분의 백슬래시가 필요하지 않아 코드를 시각적으로 단순화합니다.grep그리고sed

grep -Ef <(sed 's/.*/^([^\t]+\t){2}([^\t]+,)*&[,\t]/' file1) file2

grep의 확장 정규식의 경우,file1다음으로 동적으로 변환됩니다.

^([^    ]+  ){2}([^ ]+,)*Locus_1[,  ]
^([^    ]+  ){2}([^ ]+,)*Locus_2[,  ]
^([^    ]+  ){2}([^ ]+,)*Locus_3[,  ]

산출(두 경우 모두):

3   3   Locus_1 Locus_40    etc_849     
3   2   Locus_2 Locus_94    *       
2   3   Locus_3,Locus_4 Locus_50    *       

알아채다-f그리고-F속도가 크게 느려질 수 있지만file1매우 크다

답변4

(   t=$(printf \\t) ntt=[^$t]*$t ntc=[^$t,]*
### ^just makes it easy regardless of your sed version.
    sed  -ne"s/..*/^($ntt){2}($ntc,)*&(,$ntc)*$t/p" |
    grep -Ef- ./File2
)   <File1

3   3   Locus_1 Locus_40    etc_849
3   2   Locus_2 Locus_94    *
2   3   Locus_3,Locus_4 Locus_50    *

($ntc,)*그러면 앞이나 (,$ntc)*뒤의 그룹 수 에 관계없이 File2의 세 번째 열과 File1의 행이 일치합니다 . 그러나 이는 File1의 검색 문자열에 메타 문자가 없는지에 따라 달라집니다. File1에 메타문자가 있을 수 있는 경우 먼저 이를 정리해야 합니다.

(   t=$(printf \\t) ntt=[^$t]*$t ntc=[^$t,]*
    sed  -ne's/[]?{(^$|*.+)}\[]/\\&/g' \
          -e"s/..*/^($ntt){2}($ntc,)*&(,$ntc)*$t/p" |
    grep -Ef- ./File2
)   <File1

관련 정보