Это требует рефакторинга, но должно делать то, что вы хотите:
while IFS=; read -r line; do grep -Fw "$line" biffile.txt; done < other_file | awk -F';' '{split($3,a,"=");print a[2]}'
Попробуйте это,
grep "ID=$pattern;" file | grep -o 'Name=[^;]*' | sed 's/Name=//g';
grep -o 'Name=[^;]*'
с помощью grep шаблон начинается с "Name=" и немедленно заканчивается ";" sed 's/Name=//g';
просто удалите шаблон, который не требуется в соответствии с вашими требованиями. Предполагая, что это 9-я вкладка -поле с разделителями файла GFF(поле «атрибуты» ), вы можете извлечь значение атрибута gene
, соответствующее конкретному ID
атрибут (читается из отдельного файла )вот так сawk
:
BEGIN { FS = "\t" }
FNR == NR {
# Read IDs into a hash as keys.
ids[$1] = 1
next
}
$3 == "gene" {
# Split the attribute field into separate key-value pairs.
n = split($9, keyvalues, ";")
id = "" # Not found a gene ID yet
gene = "" # No gene name to print
# Loop over the key-value pairs, split them on the "="
# and extract the gene name and gene ID.
for (i = 1; i <= n; ++i) {
split(keyvalues[i], attr, "=")
if (attr[1] == "ID") {
if (attr[2] in ids)
id = attr[2]
else
next # This line is not of interest
}
else if (attr[1] == "gene")
gene = attr[2]
}
if (id != "" && gene != "")
print gene
}
Запуск этого в файле GFF с именем file.gff
, содержащем заданные данные в столбце 9 и со списком идентификаторов генов в id.list
:
$ awk -f script.awk id.list file.gff
LOC108565285
LOC108569527
Список идентификаторов генов считывается из первого файла в блоке FNR == NR
в коде awk
, тогда как последний блок обрабатывает атрибутивное поле характерных линий генов (только )во втором (и все последующие )файлы, заданные в командной строке.
Код awk
предполагает, что атрибуты ID
и gene
файла GFF содержат только одно значение (без запятой -список значений с разделителями )и что значения не цитируется.
Чтобы получить вывод в виде списка имен генов и идентификаторов генов (два столбца ), измените оператор print gene
на print id, gene
.
Я бы использовал немного другой подход. Первый,извлечь только поля ID и Name:
$ sed -nE 's/.*ID=([^;]*).*Name=([^;]*).*/\1 \2/p' file1
gene27 LOC108565285
gene28 LOC108569527
gene78 LOC108562956
Затем отфильтруйте это, используя список целевых идентификаторов:
$ cat file2
gene27
gene28
$ sed -nE 's/.*ID=([^;]*).*Name=([^;]*).*/\1 \2/p' file1 | grep -wf file2
gene27 LOC108565285
gene28 LOC108569527
Или, если вам нужно только значение LOC....
и предполагается, что у вас есть GNUgrep
:
$ grep -wf file2 file1 | grep -oP 'Name=\K[^;]+'
LOC108565285
LOC108569527
Выполняется простым скриптом ниже
команда
for i in `cat file2`; do awk -v i="$i" -F ";" '$1=="ID="i{print $5}' file1| awk -F "=" '{print $NF}'; done
выход
LOC108565285
LOC108569527
Сейф. Простой. Короткий.
Название bigfile.txt
предполагает, что мы не хотим выполнять grep несколько раз, а делаем это за один проход. Поэтому я предпочитаю попытку, подобную @Kusalananda :Соберите все идентификаторы генов для извлечения, а затем просканируйте один раз через bigfile
. Для такой задачи я предпочитаю sed
, так как вам не нужно иметь дело с программированием, таким как переменные, массивы и циклы, просто позвольте инструменту сделать всю работу:
sed '/^gene[0-9]*$/{s/$/;/;H;d;};G;/ID=\(gene[0-9]*;\).*\n\1/!d;s/.*gene=\(LOC[0-9]*\);.*/\1/' genelist.txt bigfile.txt
А вот и объяснение:
/^gene[0-9]*$/
— шаблон для выбора строк списка :просто gene
с номером {s/$/;/;H;d;}
выполняется только для строк выше:s/$/;/
добавляет ;
, H
добавляет эту измененную строку в область хранения и d
останавливает дальнейшую обработку и удаляет строку bigfile.txt
и пространство хранения заполнено всеми идентификаторами генов. Теперь G
добавляет этот список в пространство шаблонов /ID=\(gene[0-9]*;\).*\n\1/
выбирает строки, в которых ID gene[0-9]*
повторяется (\1
относится к строке внутри первой пары\(\)
)после новой строки,таким образом, идентификатор, который присутствует в списке !d
инвертирует выделение и удаление, чтобы все строки без совпадений удалялись gene
:s/.*gene=\(LOC[0-9]*\);.*/\1/
Попробуйте это
grep "ID=gene[0-9]" bigfile.txt | sed 's/\;/ /g' | awk '{print $3}' | sed 's/Name=//g'