Как извлечь общие черты между двумя строками

Можно использовать awk. Поместите следующее в сценарий, script.awk:

FNR == NR {
  f1[$1,$2,$4] = $0
  f1_c14[$1,$2,$4] = 1
  f1_c5[$1,$2,$4] = $5
  next
}  

f1_c14[$1,$2,$4] {
  if ($5 != f1_c5[$1,$2,$4]) print f1[$1,$2,$4];
}

f1[$1,$2,$4] {
  if ($5 != f1_c5[$1,$2,$4]) print $0;
}

Теперь выполните его как это:

$ awk -f script.awk file1  file2
sc2/80         20      .        A       T         86       PASS     N=2     F=5;U=4
sc2/80         20      .        A        C        80      PASS    N=2       F=5;U=4
sc2/60         55      .        G       T         76       PASS     N=2     F=5;U=4 
sc2/60         55      .        G        C        72      PASS    N=2       F=5;U=4

Сценарий работает следующим образом. Этот блок создает 3 массива, f1, f1_c14, и f1_c5. f1 содержит все строки file1 в массиве, индексированное использование содержания столбцов 1, 2, и 4 от file1. f1_c14 другой массив с тем же индексом (1, 2, и 4's содержание) и значение 1. 3-й массив использует тот же индекс в качестве 1-х 2 со значением 5-го столбца от file1.

FNR == NR {
  f1[$1,$2,$4] = $0
  f1_c14[$1,$2,$4] = 1
  f1_c5[$1,$2,$4] = $5
  next
} 

Следующий блок ответственен за печать строк из 1-го файла, file1 при условиях, от которых столбцы 1, 2, и 4 соответствуют столбцам file2, И это будет onlu распечатать строку от file1 если 5-е столбцы file1 и file2 не соответствовать.

f1_c14[$1,$2,$4] {
  if ($5 != f1_c5[$1,$2,$4]) print f1[$1,$2,$4];
}

3-й блок ответственен за печать связанной строки от file2 в массиве существует соответствующая строка f1 для file2столбцы 1, 2, и 4. Снова это только печатает, если 5-е столбцы не соответствуют.

f1[$1,$2,$4] {
  if ($5 != f1_c5[$1,$2,$4]) print $0;
}

Пример

Выполнение вышеупомянутого сценария как так:

$ awk -f script.awk file1  file2
sc2/80         20      .        A       T         86       PASS     N=2     F=5;U=4
sc2/80         20      .        A        C        80      PASS    N=2       F=5;U=4
sc2/60         55      .        G       T         76       PASS     N=2     F=5;U=4 
sc2/60         55      .        G        C        72      PASS    N=2       F=5;U=4 

Можно использовать column управляйте для чистки вывода немного:

$ awk -f script.awk file1  file2 | column -t
sc2/80  20  .  A  T  86  PASS  N=2  F=5;U=4
sc2/80  20  .  A  C  80  PASS  N=2  F=5;U=4
sc2/60  55  .  G  T  76  PASS  N=2  F=5;U=4
sc2/60  55  .  G  C  72  PASS  N=2  F=5;U=4

Как это работает?

FNR == НОМЕР

Это использует awkспособность циклично выполниться через файлы конкретным способом. Вот, мы - цикличное выполнение через файлы и когда мы находимся на строке, это из первого файла, file, мы хотим выполнить конкретный блок кода на этой строке от file1.

Этот пример показывает что FNR == NR делает, когда мы даем ему 2 моделируемых файла. У каждого есть 4 строки в нем, в то время как другой имеет 5 строк:

$ awk 'BEGIN {print "NR\tFNR\tline"} {print NR"\t"FNR"\t"$0}' \
     <(seq 1 4) <(seq 1 5)
NR  FNR line
1   1   1
2   2   2
3   3   3
4   4   4
5   1   1
6   2   2
7   3   3
8   4   4
9   5   5
другие блоки

Другие блоки, f1_c14[$1,$2,$4] И f1[$1,$2,$4] только выполненный, когда значения от тех элементов массива имеет значение.

3
30.04.2014, 13:58
4 ответа

Я не могу придумать способ использования простого регулярного выражения, поскольку то, что вы делаете, немного сложно.

В языке вроде Ruby вы можете разбить строки на массив слов, разделенных пробелами, с помощью регулярного выражения ( \ s + ) и получить ] пересечение ( и ) двух результирующих массивов.

"30 mutation alanine for valine".split( /\s+/ ) & "alanine at position 30".split( /\s+/ )
=> ["30", "alanine"]

Пробелы используются по умолчанию для разделения в Ruby, поэтому их можно сократить до

"30 mutation alanine for valine".split & "alanine at position 30".split
1
27.01.2020, 21:11

Может быть, wdiff может вам помочь? Поместите строки в два файла, а затем сравните их с wdiff :

echo "30 mutation alanine for valine" > file1
echo "alanine at position 30" > file2
wdiff -t file1 file2

Снимок экрана вывода:

Screenshot of the output

3
27.01.2020, 21:11

Вот решение awk:

$ awk '{for(i=1;i<=NF;i++){a[$i]++}}
    END {
        for(i in a) {
            if(a[i] > 1) {
                print i
            }
        }
    }' file1 file2
30
alanine
0
27.01.2020, 21:11

Вы можете проверить слова, которые появляются в обеих строках:

$ comm -12 <(sed 's/ /\n/g' <<<$str1 | sort) <(sed 's/ /\n/g' <<<$str2 | sort )
30
alanine

Пояснение

  • Команда comm сравнивает файлы. С флагами -1 и -2 он будет печатать те строки, которые находятся в обоих файлах.

  • sed 's / / \ n / g' <<< $ str1 | sort : это просто заменяет все пробелы на новые строки в $ str1 , выводит на стандартный вывод, который затем передается через sort , потому что comm нуждается в своих входных файлах быть отсортированным. Подробнее о формате <<< $ var см. Bash: Here Strings .

  • Формат <(команда) называется подстановкой процесса, подробнее об этом здесь .

Конечным результатом приведенной выше команды будет список всех слов, которые встречаются в обеих строках.

4
27.01.2020, 21:11

Теги

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