두 개의 파일이 있습니다.
파일 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