Использование переменных в хвостовой команде - PullRequest
1 голос
/ 02 апреля 2019

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

Например, справочный файл выглядит так:

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
... 

Кто-нибудь может сказать мне, что я делаю не так? Спасибо!

Ответы [ 3 ]

3 голосов
/ 02 апреля 2019

Похоже, вы пытаетесь получить доступ к переменной list в вашей хвостовой команде. Вы можете получить к нему доступ следующим образом: $list, а не просто использовать кавычки вокруг него.

Ваша логика несовершенна даже после исправления доступа к переменной. Переменная list включает в себя все строки вашего файла list.txt. Включая символ новой строки \n, который невидим во многих интерфейсах и программах, но, конечно, он виден, когда вы вручную читаете отдельные байты. Вам нужно кормить строки одну за другой, чтобы она работала правильно.

Кроме того, если эти числа не являются индексами с конца, вам нужно передавать их в голову вместо хвоста.

Если я понял, что вы пытаетесь сделать правильно, это должно сработать:

while read line
do
  head -c $line ref.txt | tail -c 1 >> out.txt
done < pos.txt
2 голосов
/ 02 апреля 2019

Причина вашей неудачной команды проста.Переменная 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
1 голос
/ 02 апреля 2019

Вы можете использовать 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
...