file1
HIB12
VH6|KB4
KB4
KB4|LKM98|HIB12
file2
c1 c1 c3 c4 HIB12|LKM98 c6
c1 c1 c3 c4 KB4|LKM98 c6
c1 c1 c3 c4 LL15|VH6
c1 c1 c3 c4 ZZ16|YY15 c6
c1 c1 c3 c4 ZZ16 c6
c1 c1 c3 c4 AB1 c6
두 파일 모두 탭으로 구분됩니다. 파일 1의 열 1은 파일 2의 열 5와 부분적으로 일치합니다. 두 열의 값은 "|"로 구분됩니다. file1의 열 1의 값이 파일 5의 열 5의 값과 일치하면 해당 행은 출력에 인쇄되지 않아야 하며 출력에 일치하지 않는 다른 행이 있어야 합니다. . 시도했지만 예상한 결과를 얻지 못했습니다.
awk 'BEGIN{FS=OFS="\t"} NR==FNR {a[$1]=$5; next} {for (i in a) if (index(i, $5)) print $0, a[i]}' file2 file1
expected output
c1 c1 c3 c4 ZZ16|YY15 c6
c1 c1 c3 c4 ZZ16 c6
답변1
GNU awk를 사용하는 다중 문자 RS:
$ awk '
NR==FNR { a[$0]; next }
{ split($5,v,"|"); for (i in v) if (v[i] in a) next; print }
' FS='\t' RS='[[:space:]|]+' file1 RS='\n' file2
c1 c1 c3 c4 ZZ16|YY15 c6
c1 c1 c3 c4 ZZ16 c6
c1 c1 c3 c4 AB1 c6
또는 awk를 사용하십시오.
$ awk '
NR==FNR { for (i=1; i<=NF; i++) a[$i]; next }
{ split($5,v,"|"); for (i in v) if (v[i] in a) next; print }
' FS='|' file1 FS='\t' file2
c1 c1 c3 c4 ZZ16|YY15 c6
c1 c1 c3 c4 ZZ16 c6
c1 c1 c3 c4 AB1 c6
답변2
모든 awk와 호환됩니다.
awk 'BEGIN{FS=OFS="\t"}NR==FNR{split($0,vals,"|");for(i in vals){v[vals[i]]}}NR!=FNR{hide=0;for(j in v){if($5~j){hide=1}};if(!hide){print}}' ./file1 ./file2
내 결과는 다음과 같습니다
c1 c1 c3 c4 ZZ16|YY15 c6
c1 c1 c3 c4 ZZ16 c6
c1 c1 c3 c4 AB1 c6
설명하다:
NR==FNR
: 첫 번째 파일에서는 동일합니다 NR
.FNR
{v[vals[i]]}
:값을 허용하지 않는 연관 배열을 만듭니다.
if($5~j){hide=1}
: 5번째 필드에 허용되지 않는 값이 있는 경우 숨겨진 행을 설정합니다.
hide=0
:새 행의 숨겨진 상태를 재설정합니다.
답변3
$ perl -lane '
# is this the first file? ($fc is file counter)
if ($fc == 0) {
# split first field on pipe chars
my @p = split /\|/, $F[0];
# use as keys for %patterns hash
foreach my $p (@p) { $patterns{$p} = 1 };
} else {
print unless $F[4] =~ /$regex/;
};
if (eof) { # end of file
if ($fc == 0) { # is this still the first (zeroth) file?
# use keys of %patterns to build a regular expression
$regex = join "|", keys %patterns;
};
$fc++;
}' file1 file2
c1 c1 c3 c4 ZZ16|YY15 c6
c1 c1 c3 c4 ZZ16 c6
c1 c1 c3 c4 AB1 c6
그런데, 여기에 중간 변수가 적고 주석이 없는 더 짧은 버전이 있습니다.
perl -lane '
if ($fc == 0) {
foreach (split /\|/, $F[0]) { $patterns{$_} = 1 };
} else {
print unless $F[4] =~ /$regex/;
};
if (eof) {
$regex = join "|", keys %patterns if ($fc == 0);
$fc++;
}' file1 file2
읽을 수 없게 만들고 싶다면 변수 이름을 줄이고 ($c==0)
테스트를 더 짧지만 동등한 테스트로 바꾸고(초보자에게는 이해하기 더 어렵기 때문에 보너스입니다!) (!$c)
모든 것을 한 줄로 압축하고 추가 공백을 제거하고 반 문자 - 콜론아니요운영 방식을 변경하세요. 어떤 사람들은 이것을 선호합니다 - 마조히즘적인 화물 숭배 FTW!
perl -lane 'if(!$c){foreach(split/\|/,$F[0]){$p{$_}=1}}else{print unless $F[4]=~/$regex/};if(eof){$regex=join"|",keys %p if(!$c);$c++}' file1 file2
답변4
두 번째 파일에서 다섯 번째 필드에는 이미 논리 요소 OR이 포함되어 있습니다.
awk '
NR==FNR {A[$1]; next}
{for(i in A)
if(i ~ "^("$5")$") next
print}
' RS='[\n|]' file1 RS='\n' file2
이제 조건식 줄의 시작과 끝과 괄호의 앵커 포인트만 교체하면 됩니다.