#bash #tail
#bash #tail
Вопрос:
Я пытаюсь экспортировать символы из файла ссылки, в котором известна их позиция в байтах. Для этого у меня есть длинный список чисел, сохраненных в виде переменной, которые использовались в качестве входных данных для команды tail.
Например, файл ссылки выглядит как:
ggaaatgcattcaaacatgc
И список выглядит так:
5
10
7
15
Я пытался использовать этот код:
list=$(<pos.txt)
echo "$list"
cat ref.txt | tail -c "list" | head -c1 > out.txt
Однако он продолжает возвращать «недопустимое количество байтов: ‘ 5 n10 n7 n15 …'»
Мой ожидаемый результат был бы
a
t
g
a
...
Кто-нибудь может сказать мне, что я делаю не так? Спасибо!
Комментарии:
1. У меня такое чувство, что вы обрабатываете какую-то часть файла fasta, и проблема, которую вы публикуете, является XY-проблемой. Т. Е. вы задаете этот вопрос, чтобы решить другую проблему, которая могла бы быть решена более эффективно другим способом.
2. С биологической точки зрения список представляет позиции вариаций (SNP) в файле ссылки. Код пытается найти, какой исходный символ в файле ссылок находится в этих позициях. Я надеюсь, что это поможет
3. Этот подход не будет работать должным образом с файлами fasta, потому что
head
,tail
и т.д. Все работают по позициям символов, а не по базовым позициям. То есть они не знают, что нужно пропускать заголовок, комментарии или даже перевод строки между строками. Вам действительно нужны инструменты, которые знают, как анализировать файлы fasta.
Ответ №1:
Похоже, вы пытаетесь получить доступ к своей list
переменной в своей хвостовой команде. Вы можете получить к нему доступ следующим образом: $list
вместо того, чтобы просто заключать его в кавычки.
Ваша логика ошибочна даже после исправления доступа к переменной. list
Переменная включает в себя все строки вашего list.txt
файла. Включая символ новой строки n
, который невидим во многих пользовательских интерфейсах и программах, но, конечно, виден, когда вы вручную считываете отдельные байты. Вам нужно вводить строки одну за другой, чтобы она работала должным образом.
Кроме того, если эти числа не являются индексами с конца, вам нужно передать их в head вместо tail .
Если я правильно понял, что вы пытаетесь сделать, это должно сработать:
while read line
do
head -c $line ref.txt | tail -c 1 >> out.txt
done < pos.txt
Ответ №2:
Причина сбоя вашей команды проста. Переменная list
содержит многострочную строку, сохраненную из pos.txt
файлов, включая новые строки. Вы не можете передать не более одного целого значения для -c
флага.
Ваши попытки можно довольно легко исправить, удалив вызовы cat
и используя временную переменную для хранения содержимого файла
while IFS= read -r lineNo; do
tail -c "$lineNo" ref.txt | head -c1
done < pos.txt
Но тогда, если ваши намерения каждый раз выводить желаемый результат в новой строке, head
не выводится таким образом. Он просто формирует строку atga
для вашего ввода в одной строке, а не в нескольких строках с одним символом в каждой строке.
Как упоминает Гордон в одном из комментариев, для гораздо более эффективной обработки файлов FASTA вы могли бы просто использовать один вызов awk
, хотя (пропуская несколько разветвлений на head
/ tail
). Предоставленные вами входные данные не содержат заголовков для пропуска, которые были бы простыми, поскольку
awk ' FNR==NR{ n = split($0,arr,""); for(i=1;i<=n;i ) hash[i] = arr[i] }
( $0 in hash ){ print hash[$0] } ' ref.txt pos.txt
Ответ №3:
Вы могли бы использовать cut
вместо tail
:
pos=$(<pos.txt)
cut -c ${pos//$'n'/,} --output-delimiter=$'n' ref.txt
Или просто awk:
awk -F '' 'NR==FNR{c[$0];next} {for(i in c) print $i}' pos.txt ref.txt
оба дают:
a
g
t
a