Удалите строку в файле A, если строка в файле B соответствует нескольким столбцам в файле A, поместите совпадающие строки в файл C и несогласованные строки в файле D

У меня есть 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
-2
10.08.2017, 13:59
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 остается неизменным.

Поток точно такой же, как и в предыдущем запросе, добавлена ​​полевая обработка.

0
28.01.2020, 05:16

Использование:./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"
1
28.01.2020, 05:16

Используйте скрипт 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
1
28.01.2020, 05:16

Теги

Похожие вопросы