나는 다음을 수행하려고 노력했습니다.
- 3개의 숫자 열이 있는 파일이 있고 1개의 숫자 열이 있는 더 작은 파일과 비교하여 일치하는 행을 인쇄하고 싶었습니다.
- 나는 사용하고 있지만
grep -F
항상 일치하지 않는 행을 제공합니다.
답변1
내 생각엔 101
더 작은 파일이 포함될 때 10
일치하는 것과 같은 것을 보게 될 것입니다. 이는 10이 101의 하위 문자열이기 때문입니다.
기본 파일에 필드가 하나만 있는 경우 -x
정확한 일치를 위해 grep 옵션을 사용할 수 있습니다. 예를 들어
grep -x -F -f smallerfile.txt mainfile.txt
3개의 필드가 있기 때문에 각 필드를 개별적으로 일치시켜야 하므로 perl이나 awk 같은 것을 사용해야 합니다. 예를 들어 awk를 사용하면 다음과 같습니다.
$ cat smallerfile.txt
1
10
25
152
$ cat mainfile.txt
1 2 3
5 10 15
10 11 12
100 101 102
150 151 152
250 255 260
$ awk 'FNR == NR { nums[$1]++ ; next }
$1 in nums || $2 in nums || $3 in nums' smallerfile.txt mainfile.txt
1 2 3
5 10 15
10 11 12
150 151 152
그런데 세 개 이상의 필드를 확인해야 하면 스크립트를 작성하거나 업데이트하는 것이 지루해집니다. 이를 방지하려면 각 필드(수에 관계없이)를 반복하고 그 중 하나의 값이 배열에 있는지 확인하는 awk 함수를 작성할 수 있습니다 nums
. 예를 들어
$ awk 'function check_all_fields() {
for (i=1; i<=NF; i++) {
if ($i in nums) return 1
}
return 0
}
FNR == NR { nums[$1]++ ; next }
check_all_fields()' smallerfile.txt mainfile.txt
1 2 3
5 10 15
10 11 12
150 151 152
보시다시피 출력은 첫 번째 버전과 동일합니다.
check_all_fields()
함수가 입력 행에서 일치하는 필드를 확인하면 1(true)을 반환합니다. 현재 행에 1이 전혀 표시되지 않으면 0(false)을 반환합니다.
답변2
우리는 이웃을 활용하여 검색 문자열을 sed
안내 하는 다음 접근 방식을 사용하여 이를 수행할 수 있습니다.grep
sed -e 's/.*/\\<&\\>/' f1 | grep -Ef - f3col
산출:-
1 2 3
5 10 15
10 11 12
150 151 152
awk
그림과 같이 조작 할 수 있습니다. 먼저 a[...]
단일 열 파일의 열을 기준으로 하는 연관 배열을 형성합니다. 그런 다음 3열 파일의 각 행에서 플래그를 초기화 p
하고 단일 열 파일의 필드와 일치하는 데이터가 있으면 플래그를 증가시킵니다. 그런 다음 for 루프가 끝날 때 플래그가 적어도 한 번 증가하면 조건부로 레코드를 인쇄합니다.
awk '
NR==FNR{a[$1];next}
{
for (p=i=1; i<=NF; i++) if ($i in a) p++
}p>1
' f1 f3col
python
데이터 구조 자체는 set
아래와 같이 집합의 교집합이 비어 있지 않은 경우를 인쇄하는 구현을 지원합니다.
python3 -c 'import sys
file1,file2 = sys.argv[1:]
with open(file1) as f1, open(file2) as f2:
s1 = { _.rstrip() for _ in f1 }
for _ in f2:
s2 = set(_.rstrip().split())
if bool(s2 & s1):
print(_,end="")
' f1 f3col
구문을 사용하여 POSIX sed
먼저 단일 열 파일을 사용하여 POSIX sed 코드를 생성한 다음 이를 3열 파일에 적용합니다.
sed -e '
h;G;G
s/.*/^&$/
s|\n| /b&/ |g
s|.*|/&/b|;$a\
d
' f1 | sed -f - f3col
perl
이 작업은 여러 가지 방법으로 수행할 수 있습니다.
perl -lane '
@A || chomp(@A=<STDIN>);
for my $f (@F) {
print,last if grep { $f == $_ } @A;
}
' f3col < f1
perl -MList::Util=any -lane '
chomp(@A=<STDIN>) if !@A;
print if
any {
my $f = $_;
any { $_ == $f } @A;
} @F;
' f3col < f1