我有两个文本文件:string.txt 和 lengths.txt
字符串.txt:
abcdefghijklmnopqrstuvwxyz
长度.txt
5
4
10
7
我想获取文件
>Entry_1
abcde
>Entry_2
fghi
>Entry_3
jklmnopqrs
>Entry_4
tuvwxyz
我正在处理大约 28,000 个条目,它们的字符数在 200 到 56,000 之间。
目前,我正在使用:
start=1
end=0
i=0
while read read_l
do
let i=i+1
let end=end+read_l
echo -e ">Entry_$i" >>outfile.txt
echo "$(cut -c$start-$end String.txt)" >>outfile.txt
let start=start+read_l
echo $i
done <lengths.txt
但这是非常低效的。还有更好的想法吗?
答案1
一般来说,你不想使用 shell 循环来处理文本。在这里,我会使用perl
:
$ perl -lpe 'read STDIN,$_,$_; print ">Entry_" . ++$n' lengths.txt < string.txt
>Entry_1
abcde
>Entry_2
fghi
>Entry_3
jklmnopqrs
>Entry_4
tuvwxyz
那是一命令,该命令(使用缓冲,比read
一次读取一个字节(或常规文件的几个字节)的 shell 命令更有效)两个文件仅读取一次(不会将它们完全存储在内存中),所以将比在 shell 循环中运行外部命令的解决方案效率高几个数量级。
(-C
如果这些数字应该是当前区域设置中的字符数而不是字节数,请添加该选项。对于示例中的 ASCII 字符,这不会产生任何区别)。
答案2
你可以做
{
while read l<&3; do
{
head -c"$l"
echo
} 3<&-
done 3<lengths.txt
} <String.txt
它需要一些解释:
主要思想是使用{ head ; } <file
并源自被低估的@mikeserv回答。然而,在这种情况下,我们需要使用许多head
s,因此while
引入了循环并对文件描述符进行了一些调整,以便传递到head
两个文件的输入(文件String.txt
作为要处理的主文件,行length.txt
作为选项的参数-c
) 。这个想法是,速度上的好处应该来自于不需要每次调用类似或 之String.txt
类的命令时都进行搜索。只是在每次迭代后打印换行符。head
cut
echo
它的速度有多快(如果有的话)以及>Entry_i
在行之间添加内容作为练习。
答案3
bash,版本 4
mapfile -t lengths <lengths.txt
string=$(< String.txt)
i=0
n=0
for len in "${lengths[@]}"; do
echo ">Entry_$((++n))"
echo "${string:i:len}"
((i+=len))
done
输出
>Entry_1
abcde
>Entry_2
fghi
>Entry_3
jklmnopqrs
>Entry_4
tuvwxyz
答案4
关于什么awk
?
创建一个使用以下代码调用的文件process.awk
:
function idx(i1, v1, i2, v2)
{
# numerical index comparison, ascending order
return (i1 - i2)
}
FNR==NR { a[FNR]=$0; next }
{ i=1;PROCINFO["sorted_in"] = "idx";
for (j in a) {
print ">Entry"j;
ms=substr($0, i,a[j])
print ms
i=i+length(ms)
}
}
保存并执行awk -f process.awk lengths.txt string.txt