在 tail 命令中使用变量

Utilising variables in tail command

我正在尝试从字节位置已知的参考文件中导出字符。为此,我将一长串数字存储为变量,用作 tail 命令的输入。

例如,参考文件如下所示:

ggaaatgcattcaaacatgc

列表如下:

5
10
7
15

我试过使用这个代码:

list=$(<pos.txt)
echo "$list"
cat ref.txt | tail -c +"list" | head -c1 > out.txt

但是,它一直在返回"invalid number of bytes: '+5\n10\n7\n15...'"

我的预期输出是

a
t
g
a
... 

谁能告诉我我做错了什么?谢谢!

您似乎正试图在 tail 命令中访问 list 变量。您可以像这样访问它:$list 而不是只在它周围使用引号。

即使修复了变量访问,您的逻辑仍然存在缺陷。 list 变量包含 list.txt 文件的所有行。包括换行符\n,在很多UI和程序中是看不到的,但是手动读取单个字节时当然是看得见的。您需要一条一条地馈线才能使其正常工作。

此外,除非这些数字是末尾的索引,否则您需要将它们提供给头部而不是尾部。

如果我正确理解了您的尝试,那么这应该有效:

while read line
do
  head -c $line ref.txt | tail -c 1 >> out.txt
done < pos.txt

你的命令失败的原因很简单。变量 list 包含从 pos.txt 文件中存储的 multi-line 字符串,包括换行符。您不能为 -c 标志传递不超过一个整数值。

通过删除对 cat 的调用并使用临时变量来保存文件内容,可以很容易地修复您的尝试

while IFS= read -r lineNo; do
    tail -c "$lineNo" ref.txt | head -c1
done < pos.txt

但是如果你的意图是每次都在 new-line 中打印所需的输出,head 不会那样输出。它只是在一行中为您的给定输入形成一个字符串 atga,而在多行中 not 每行一个字符。

正如 Gordon 在其中一条评论中提到的那样,为了更高效地处理 FASTA 文件,您可以只使用一次 awk 调用(跳过多个分支到 head/tail).您提供的输入不涉及任何要跳过的 headers,这很简单,因为

awk ' FNR==NR{ n = split([=11=],arr,""); for(i=1;i<=n;i++) hash[i] = arr[i] } 
      ( [=11=] in hash ){ print hash[[=11=]] } ' ref.txt pos.txt

您可以使用 cut 而不是 tail:

pos=$(<pos.txt)
cut -c ${pos//$'\n'/,} --output-delimiter=$'\n' ref.txt

或者只是 awk:

awk -F '' 'NR==FNR{c[[=11=]];next} {for(i in c) print $i}' pos.txt ref.txt

两者都产生:

a
g
t
a