У меня есть файл, который похож на это
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
Так, с логической точки зрения я хочу
grep
строки, которые я ищу, только если они - весь подарок в каждом блоке Таким образом, если я понимаю Вас правильно, Вы хотите найти все подгруппы, которые содержат ВСЕ шаблоны, которые Вы определяете. Это может быть сделано с 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
Что-то вроде этого?
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
Конечно, не столь простой как grep
. Эта программа:
grep
и соберите вывод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
Следующее 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
Может быть сделан в 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 потоку сценария, считай поток линию за линией, и для каждой строки мы делаем поиск в списке аргументов, что мы обеспечиваем на командной строке. Довольно простой подход