Grep представляет в виде строки в подгруппе строк в txt файле

У меня есть файл, который похож на это

AAA_21               PF13304.1  x_00004
AAA_22               PF13401.1  x_00004
SMC_N                PF02463.14 x_00004
AAA_29               PF13555.1  x_00004
DUF258               PF03193.11 x_00005
AAA_15               PF13175.1  x_00005
AAA_21               PF13304.1  x_00005
AAA_22               PF13401.1  x_00005
SMC_N                PF02463.14 x_00005
AAA_15               PF13175.1  x_00006
AAA_21               PF13304.1  x_00006
AAA_22               PF13401.1  x_00007
SMC_N                PF02463.14 x_00007

Теперь, для каждого блока строк, которые имеют ту же строку в столбце 3 (например, x_00004), я хочу grep только строки, содержащие определенные строки, если они присутствуют вместе в блоке.

Так, я знаю, что могу использовать grep -f <file containing string> <file to scan> Но я не могу найти путь к применению первого действия. Я предполагаю awk поможет мне здесь, но я действительно не знаю как.

Я хотел бы иметь что-то как:

AAA_21               PF13304.1  x_00004
AAA_22               PF13401.1  x_00004
AAA_21               PF13304.1  x_00005
AAA_22               PF13401.1  x_00005

Так в основном хватание строк, содержащих PF13304.1 или PF13401.1 только если они совместно используют поле 3.

Я использую PF13304.1 и PF13401.1 как пример, потому что иногда я ищу присутствие 3 строк в блоке. Одна проблема состоит в том, что строка, которую я ищу, не всегда последовательна в файле, который я хочу просканировать.

Все строки я хочу grep сообщаются в txt файле также. Я могу организовать их, поскольку я хочу соответствовать grep команда.

Вместо этого строка, содержащая

AAA_21               PF13304.1  x_00006
AAA_22               PF13401.1  x_00007

Не должен быть включен, потому что строки я хочу grep не совместно используйте поле 3, подразумевая, что они оба не присутствуют в подгруппах x_00006 или x_00007

Так, с логической точки зрения я хочу

  1. откройте файл
  2. разделите строки на группы соответственно с полем 3, создайте группу, которые имеют ту же строку в поле 3
  3. в этом подгруппы grep строки, которые я ищу, только если они - весь подарок в каждом блоке
3
задан 16 February 2015 в 20:06

5 ответов

Таким образом, если я понимаю Вас правильно, Вы хотите найти все подгруппы, которые содержат ВСЕ шаблоны, которые Вы определяете. Это может быть сделано с sort и awk, например:

# make sure subgroups are adjacent 
sort -k3,3 infile |

# add a newline between subroups, this allows the next 
# invocation of awk to read each subgroup as a record
awk 'NR > 1 && p!=$3 { printf "\n" } { p=$3 } 1' |   

# match the desired patterns and print the subgroup name
awk '/\<PF13304\.1\>/ && /\<PF13401\.1\>/ { print $3 }' RS=

Вывод:

x_00004
x_00005

На основе вышеупомянутого вывода можно теперь извлечь соответствующие строки от infile, например, добавить следующее к вышеупомянутому каналу:

while read sgrp; do
  grep -E "\b(PF13304\.1|PF13401\.1)\b +$sgrp\$" infile
done

Вывод:

AAA_21               PF13304.1  x_00004
AAA_22               PF13401.1  x_00004
AAA_21               PF13304.1  x_00005
AAA_22               PF13401.1  x_00005
0
ответ дан 1 December 2019 в 17:38

Что-то вроде этого?

awk '(/x_00004/ || /x_00005/) && (/PF13401.1/ || /PF13304.1/)' your_file

или это, преимущественно то же, но с более читаемой группировкой

awk '(/x_00004/ && (/PF13401.1/ || /PF13304.1/)) || (/x_00005/ && (/PF13401.1/ || /PF13304.1/))' your_file
<час>

Пример

входной файл

cat foo

AAA_21               PF13304.1  x_00004
AAA_22               PF13401.1  x_00004
SMC_N                PF02463.14 x_00004
AAA_29               PF13555.1  x_00004
DUF258               PF03193.11 x_00005
AAA_15               PF13175.1  x_00005
AAA_21               PF13304.1  x_00005
AAA_22               PF13401.1  x_00005
SMC_N                PF02463.14 x_00005
AAA_15               PF13175.1  x_00006
AAA_21               PF13304.1  x_00006
AAA_22               PF13401.1  x_00007
SMC_N                PF02463.14 x_00007

команда

awk '(/x_00004/ || /x_00005/) && (/PF13401.1/ || /PF13304.1/)' foo

AAA_21               PF13304.1  x_00004
AAA_22               PF13401.1  x_00004
AAA_21               PF13304.1  x_00005
AAA_22               PF13401.1  x_00005
0
ответ дан 1 December 2019 в 17:38

Конечно, не столь простой как grep. Эта программа:

  • сканирует текстовый файл, накапливая "блоки", где 3-е поле является той же строкой
  • когда это найдет блок, вызвать grep и соберите вывод
  • если количество строк в выводе совпадает с количеством критериев поиска, выходного вывода grep's
awk '
  function grep(block,    m, grep_out, cmd, line, i) {
    m = 0
    delete grep_out

    cmd = "grep -f " ARGV[1]    # define the grep command
    print block |& cmd          # invoke grep, and send the block of text as stdin
    close(cmd, "to")            # close greps stdin so we can start reading the output

    # read from grep until no more output
    while ((cmd |& getline line) > 0)
      grep_out[m++] = line
    close(cmd)

    # did grep find all search terms?  If yes, print the output 
    if (length(grep_out) == nterms)
      for (i=0; i<m; i++) 
        print grep_out[i]
  }

  # read the search terms file, just to count the number of lines
  NR == FNR {
    nterms++
    next
  }

  # if we detect a new block, call grep and start a new block
  section != $3 {
    if (block) grep(block)
    block = ""
    section = $3
  } 

  {block = block $0 RS}   # accumulate the lines in this block

  END {if (block) grep(block)}       # also call grep at end of file

' fileContainingStrings fileToScan 

производит этот вывод:

AAA_21               PF13304.1  x_00004
AAA_22               PF13401.1  x_00004
AAA_21               PF13304.1  x_00005
AAA_22               PF13401.1  x_00005
0
ответ дан 1 December 2019 в 17:38

Следующее awk сценарий соответствует перечисленному тому литеральных строк на строку в match_file, против data_file

awk 'function endgroup() {
         gmc=0                              # group match count
         for( gi=1; gi<=gz; gi++ ) {        # step through all lines in a group
             split(group[gi],g)             # split one group line 
             for( lix in lms )              # for each literal match string index 
                 if( lix == g[2] )          # does literal match string = group record $2  
                     mrec[++gmc]=group[gi]  # group matched record array, and inc match count
         } 
         if( gmc==lmz ) for( mri=1; mri<=lmz; mri++ ) print mrec[mri]
         delete group; gz=0
     }

     BEGIN{ p3=FS } # an impossible previous value of $3 of "data_file"

     # process "match_file"
     NR==FNR { lms[$0]   # build array with literal match strings as indices
               lmz++     # literal match strings array size 
               next } 
     # process "data_file"
     p3!=$3 && p3!=FS { endgroup() }
     { group[++gz]=$0; p3=$3 }

     END{ if( p3!=FS ) endgroup() }
' match_file data_file

Вывод:

AAA_21               PF13304.1  x_00004
AAA_22               PF13401.1  x_00004
AAA_21               PF13304.1  x_00005
AAA_22               PF13401.1  x_00005
0
ответ дан 1 December 2019 в 17:38

Может быть сделан в Python довольно легко:

$ cat input.txt | ./find_strings.py PF13304.1 PF13401.1                                                                  
AAA_21               PF13304.1  x_00004
AAA_22               PF13401.1  x_00004
AAA_21               PF13304.1  x_00005
AAA_22               PF13401.1  x_00005
AAA_21               PF13304.1  x_00006
AAA_22               PF13401.1  x_00007

Содержание find_strings.py:

#!/usr/bin/env python
import sys
strings=sys.argv[1:]
for line in sys.stdin:
    for string in strings:
         if string in line:
             print line.strip()

Путем это, которое слова - то, что мы перенаправляем содержание входного файла к stdin потоку сценария, считай поток линию за линией, и для каждой строки мы делаем поиск в списке аргументов, что мы обеспечиваем на командной строке. Довольно простой подход

1
ответ дан 1 December 2019 в 17:38

Другие вопросы по тегам:

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