У меня есть 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
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 остается неизменным.
Поток точно такой же, как и в предыдущем запросе, добавлена полевая обработка.
Использование:./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"
Используйте скрипт 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"
}
}
Сначала мы считываем строки из каждого файла в два массива, файл A и файл B, и оба имеют один и тот же ключ, т. е. «Baillie2011DonorAH84452925». Мы перебираем каждую запись в массиве fileB и проверяем наличие соответствующей записи в файле A. Если он существует,добавить запись в файл C через перенаправление печати, а также выполнить команду sed через системную функцию awk (ОСТЕРЕГАЙТЕСЬ -системная функция сопряжена с риском внедрения кода, поэтому оцените риск соответствующим образом )Если совпадений нет, выведите строка в файлеD.
Действие с:
awk -f awkscriptfile fileB fileA