在 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
我正在尝试从字节位置已知的参考文件中导出字符。为此,我将一长串数字存储为变量,用作 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