我有 2 个文件 -文件A这是包含 10 多列和大约 15,000 行的主文件,以及文件B,其中包含 4 列和约 1500 行。
我想一次获取每一行文件B,并将这些列与中的相应列相匹配文件A(两个文件之间的顺序不同,但列标题相同)。如果所有 4 列都匹配文件B在文件A,然后从中删除整行文件A,并放入一个新文件(文件C)。
我还需要任何不匹配的行文件B被放入一个新文件中(文件D)。
例子:
文件A:
individual_id study_id.x chromosome g_start gene referencel1hs SampleFile_num id sample_name
54 Baillie2011 4 57497067 na no 612 612 DonorAR2
54 Baillie2011 X 154790187 TMLHE no 612 612 DonorAR2
54 Baillie2011 5 159351203 ADRA1B no 612 612 DonorAR2
54 Baillie2011 13 79259801 na no 612 612 DonorAR2
54 Baillie2011 8 4452925 CSMD1 no 610 610 DonorAH
文件B:
study_id.x sample_name chromosome g_start
Baillie2011 DonorAH 8 4452925
Baillie2011 DonorBC 9 5491376
Baillie2011 DonorAH 8 5829283
Baillie2011 DonorCH 8 5829283
结果:
文件A:
individual_id study_id.x chromosome g_start gene referencel1hs SampleFile_num id sample_name
54 Baillie2011 4 57497067 na no 612 612 DonorAR2
54 Baillie2011 X 154790187 TMLHE no 612 612 DonorAR2
54 Baillie2011 5 159351203 ADRA1B no 612 612 DonorAR2
54 Baillie2011 13 79259801 na no 612 612 DonorAR2
文件C:
individual_id study_id.x chromosome g_start gene referencel1hs SampleFile_num id sample_name
54 Baillie2011 8 4452925 CSMD1 no 610 610 DonorAH
文件D:
study_id.x sample_name chromosome g_start
Baillie2011 DonorBC 9 5491376
Baillie2011 DonorAH 8 5829283
Baillie2011 DonorCH 8 5829283
答案1
使用 awk 脚本如下:
NR == FNR {
strt=1
}
NR != 1 && FNR ==1 {
strt=0
}
strt == 1 {
fileB[FNR"_"$1$2$3$4]=$0
}
strt == 0 {
fileA[$2$9$3$4]=$0
}
END {
for (i in fileB) {
split(i,arry,"_")
if (fileA[arry[2]] != "") {
print fileA[arry[2]] > "fileC"
system("sed -i \"/"fileA[arry[2]]"/d\"
fileA")
}
else {
print fileB[i] > "fileD"
}
}
我们首先将每个文件中的行读入两个数组,fileA 和 fileB,并且两者都具有相同的键,即“Baillie2011DonorAH84452925”。我们循环遍历 fileB 数组中的每个条目,并检查 fileA 中是否有相应的条目。如果存在,则通过打印重定向将条目添加到 fileC,并通过 awk 的系统函数执行 sed 命令(注意 - 系统函数带有代码注入风险,因此相应地评估风险)如果没有匹配,则将该行输出到文件 D.
行动:
awk -f awkscriptfile fileB fileA
答案2
用法: ./processing.sh
该脚本不会更改原始文件file_A
,而是创建new_file_A
.您可以向其中添加几行代码,用于删除原始代码file_A
并将其重命名new_file_A
为file_A
.我可以在代码中添加注释,如果可以的话,你想要什么。
#!/bin/bash
file_a="file_A.txt"
file_b="file_B.txt"
file_c="file_C.txt"
file_d="file_D.txt"
print_to_files () {
awk -v lines="$1" -v outfile1="$3" -v outfile2="$4" '
BEGIN {
cnt = 2;
split(lines,lines_arr);
}
{
if (NR == 1) {
print $0 > outfile1;
print $0 > outfile2;
} else if (NR == lines_arr[cnt]) {
print $0 >> outfile1;
cnt++;
} else {
print $0 >> outfile2;
}
}
' "$2"
}
lines_matching () {
grep -n -f <(echo "$1") <(echo "$2") | cut -d ':' -f 1
}
file_a_cols=$(awk '{printf "%s %s %s %s\n", $2, $9, $3, $4; }' "$file_a")
file_b_cols=$(tr -s ' ' < "$file_b")
matched_lines_file_a=$(lines_matching "$file_b_cols" "$file_a_cols")
matched_lines_file_b=$(lines_matching "$file_a_cols" "$file_b_cols")
print_to_files "$matched_lines_file_a" "$file_a" "$file_c" "new_$file_a"
print_to_files "$matched_lines_file_b" "$file_b" "/dev/null" "$file_d"
答案3
perl -MFatal='open,close' -ali -ne '
BEGIN{
open FILEC, ">", "FileC.out";
open FILED, ">", "FileD.out";
}
if ( @ARGV ) { # FileB readin
if ( $. == 1 ) {
push @names, @F;
print FILED $_;
} else {
push @A, join $/, @F;
push @B, $_;
}
print;
} else { # FileA readin
if ( $. == 1 ) {
print FILEC $_;
print;
@remap =
map {
my $n = $names[$_];
grep { $n eq $F[$_] } 0 .. $#F;
} 0..$#names;
} else {
my $n = join $/, @F[@remap];
if ( my($id) = grep { $n eq $A[$_] } 0 .. $#A ) {
push @IDs, $id;
print FILEC $_;
} else {
print;
}
}
}
eof and $. = 0;
END{
splice(@B, $_, 1) for @IDs;
@B and print FILED $_ for @B;
close $_ for *FILEC, *FILED;
}
' FileB FileA
此后,将创建文件“FileC.out”、FileD.out。 FileA 已修改,FileB 保持不变。
该流程与您之前的查询中一样,只是添加了归档处理。