#awk #sed #grep
Вопрос:
У меня есть текстовый файл, такой как:
>HiC_scaffold_1 LN:i:45809557 RC:i:152227 XC:f:0.987707
CAGGAAAGCCGCGTAAGTGAATATATGCAGCAACCTACCGAAAAGTGGGCCAATCCAACCAATCTTGCTTGCACAATGGAAAGAGCCACTGGTTTATCTCTCCATCGAATCAAATTAGCCAAAGGTGTGCGTTCATGAGCCCATGCTAAAGTTTCAATCAATTCTTGCCAATATCCACGCCAGGAAATTAAGAACATAAATCCAGTGCTGCAGC
>HiC_scaffold_2 LN:i:32008785 RC:i:102679 XC:f:0.981906
AAAGCTGCCCCTAGGCCGAACAAAATGGTCGGATGCGAAGAGAAATTGTTTGGCTCAAAATTTTACGAGCTTGTGCAGAACTTCAAGGCAATCATATCGGCAGGTGACACGAAGTGATTCGAGTTCGGCAGCTTTGCCCCTCCTTTTTCCTTGACGAAAGATAACTTTTTCTGAAAATAACACGTGCCCCGATTCCGGCCGAAATGACTCGAAT
>HiC_scaffold_3 LN:i:26569524 RC:i:79397 XC:f:0.996709
CCTAAACCCTAAACCCTAAACCCCTAAACCCTAAACCCTAACCCTAAACCCTAAACCCCTAAACCCTAAACCCTAAACCCTAAACCCTAAACCCTAAACCCTAAACCCTAAACCCTAAACCCTAAAACCCACCTAAACCCTAAACCCTAAACCCCCTAAACCCAAAACGCTGCCCCTAAACCCTAAACCCTAAACCCGCAGCTAACCCTAAACC
Я хотел бы найти позиции в строках, которые не начинаются с»>», в которых появляются шаблоны «GCAGC» или «GCTGC».
Есть ли способ использовать sed
или awk
возвращать оба номера строк совпадений, а также индексы совпадений в каждой строке (т. Е. Количество символов в каждой строке, с которых начинается каждое совпадение)?
Спасибо!
Комментарии:
1. Могут ли целевые строки перекрываться? Каким должен быть вывод для входной строки
fooGCAGCAGCAGCbar
?
Ответ №1:
Предполагая, что если могут возникать перекрывающиеся целевые строки, вы хотите знать обо всех из них, это будет работать с использованием любого awk в любой оболочке на каждом блоке Unix:
$ cat tst.awk
!/^>/ {
while ( match($0,/GC[AT]GC/) ) {
print NR, RSTART, substr($0,RSTART,RLENGTH)
$0 = substr($0,1,RSTART-1) " " substr($0,RSTART 1)
}
}
$ awk -f tst.awk file
2 27 GCAGC
2 207 GCTGC
2 210 GCAGC
4 4 GCTGC
4 128 GCAGC
6 169 GCTGC
6 198 GCAGC
7 4 GCAGC
7 7 GCAGC
7 10 GCAGC
Вышесказанное было выполнено в этом входном файле:
$ cat file
>HiC_scaffold_1 LN:i:45809557 RC:i:152227 XC:f:0.987707
CAGGAAAGCCGCGTAAGTGAATATATGCAGCAACCTACCGAAAAGTGGGCCAATCCAACCAATCTTGCTTGCACAATGGAAAGAGCCACTGGTTTATCTCTCCATCGAATCAAATTAGCCAAAGGTGTGCGTTCATGAGCCCATGCTAAAGTTTCAATCAATTCTTGCCAATATCCACGCCAGGAAATTAAGAACATAAATCCAGTGCTGCAGC
>HiC_scaffold_2 LN:i:32008785 RC:i:102679 XC:f:0.981906
AAAGCTGCCCCTAGGCCGAACAAAATGGTCGGATGCGAAGAGAAATTGTTTGGCTCAAAATTTTACGAGCTTGTGCAGAACTTCAAGGCAATCATATCGGCAGGTGACACGAAGTGATTCGAGTTCGGCAGCTTTGCCCCTCCTTTTTCCTTGACGAAAGATAACTTTTTCTGAAAATAACACGTGCCCCGATTCCGGCCGAAATGACTCGAAT
>HiC_scaffold_3 LN:i:26569524 RC:i:79397 XC:f:0.996709
CCTAAACCCTAAACCCTAAACCCCTAAACCCTAAACCCTAACCCTAAACCCTAAACCCCTAAACCCTAAACCCTAAACCCTAAACCCTAAACCCTAAACCCTAAACCCTAAACCCTAAACCCTAAAACCCACCTAAACCCTAAACCCTAAACCCCCTAAACCCAAAACGCTGCCCCTAAACCCTAAACCCTAAACCCGCAGCTAACCCTAAACC
fooGCAGCAGCAGCbar
Комментарии:
1. Потрясающе, большое спасибо. Вероятно, все три из этих решений работают, но я попробовал это из полного файла, и, похоже, оно работает идеально.
Ответ №2:
С perl
(неперекрывающимися):
$ perl -lne 'if(!/^>/){print join " ", $., $-[0] 1, $amp; while /GCAGC|GCTGC/g}' ip.txt
2 27 GCAGC
2 207 GCTGC
4 4 GCTGC
4 128 GCAGC
6 169 GCTGC
6 198 GCAGC
if(!/^>/)
строки, не начинающиеся с>
$.
дает номер строки$-[0]
указывает начальную позицию матча (индекс на основе 0, так1
что добавляется)$amp;
имеет совпадающую частьjoin " "
используйте пробел в качестве разделителя для объединения требуемых значенийwhile /GCAGC|GCTGC/g
переберите все совпадения для данного регулярного выражения
Чтобы также сопоставить перекрывающиеся случаи, измените регулярное /(?=(GCAGC|GCTGC))/g
выражение так, чтобы соответствующие строки теперь находились внутри группы захвата смотровой площадки. Это будет пытаться соответствовать в каждой позиции, не потребляя символов, и соответствующая часть будет доступна из $1
. Если сами поисковые запросы перекрываются (например: ABC
и ABCD
), то тот термин, который является крайним левым в чередовании, получает приоритет.
$ perl -lne 'if(!/^>/){print join " ", $., $-[0] 1, $1 while /(?=(GCAGC|GCTGC))/g}' ip.txt
2 27 GCAGC
2 207 GCTGC
2 210 GCAGC
4 4 GCTGC
4 128 GCAGC
6 169 GCTGC
6 198 GCAGC
С помощью ripgrep, который, скорее всего, будет быстрее, чем другие решения. Но недостатком является то, что это не отфильтровывает строки, начинающиеся с >
, и работает только для неперекрывающихся случаев:
$ rg --vimgrep -o --no-filename 'GCAGC|GCTGC' ip.txt
2:27:GCAGC
2:207:GCTGC
4:4:GCTGC
4:128:GCAGC
6:169:GCTGC
6:198:GCAGC
--vimgrep
предназначен для использования сvim
, который дает номера строк и столбцов-o
чтобы получить только совпадающую часть вместо всей строки--no-filename
чтобы избежать префикса имени файла в выводе- Используйте
--field-match-separator=' '
, если вам нужен разделитель пробелов вместо:
символа
Ответ №3:
Предполагая , что ваши данные находятся в файле data.txt
, простым решением было бы:
awk 'BEGIN {RS="n>";}
{ for (j=1;j<=length($i)-4;j ) {
if (substr($i,j,5) == "GCAGC") {
print "entry " NR " column " j ": GCAGC"
} else if(substr($i,j,5) == "GCTGC") {
print "entry " NR " column " j ": GCTGC"
}
}
}' data.txt
Здесь я предполагаю, что ваши записи разделены «n>», и выведите номер записи, потому что я предполагаю, что это то, что вы хотите. В противном случае вы можете просто пропустить первую часть и просто запустить
awk '{ for (j=1;j<=length($i)-4;j ) {
if (substr($i,j,5) == "GCAGC") {
print "line " NR " column " j ": GCAGC"
} else if(substr($i,j,5) == "GCTGC") {
print "line " NR " column " j ": GCTGC"
}
}
}' data.txt
что дает вам номера строк. Для получения дополнительной информации см. документацию.
Комментарии:
1. Вы должны упомянуть, что для первого скрипта требуется GNU awk для многозначных RS, он не будет работать с POSIX awk.
Ответ №4:
Вот решение, которое обрабатывает перекрывающиеся шаблоны:
BEGIN {
patternRegex = "GCAGC|GCTGC"
}
/^[^>]/ {
offset = 0
target = $0
match(target, patternRegex)
while (RSTART > 0) {
matchedString = substr(target, RSTART, RLENGTH)
printf "line %d: %s at position %dn", NR, matchedString, offset RSTART
offset = RSTART length("CG*") - 1
target = substr(target, RSTART length("CG*"))
match(target, patternRegex)
}
}
Если сценарий сохранен, find-patterns.awk
а входные input.txt
данные введены, мы получим следующий вывод:
$ awk -f find-patterns.awk < input.txt
line 2: GCAGC at position 27
line 2: GCTGC at position 207
line 2: GCAGC at position 210
line 4: GCTGC at position 4
line 4: GCAGC at position 128
line 6: GCTGC at position 169
line 6: GCAGC at position 198
Ответ №5:
Это может сработать для вас (GNU sed и ripgrep):
sed '/>/g' file | rg --column -o 'GC[AT]GC'| sed 'y/:/ /'
Пустые строки , содержащие >
, используйте ripgrep для выполнения основной части работы и очистки результата с помощью окончательного вызова sed.
Альтернатива:
rg --column -o '>|GC[AT]GC' file | sed -E 'y/:/ /;/>/h;G;/^(S* ).*n1/!P;d'
Слава Сандипу.