我有一个大文件(超过20 MB),需要拆分成更小的中继。 input.txt文件如下所示:
Rate: AAAA
.....
.....
....
Rate: AAAB
.....
.....
....
Rate: AAAC
.....
我希望输出为:
AAAA.txt:
Rate: AAAA
.....
.....
....
AAAB.txt:
Rate: AAAB
.....
.....
....
AAAC.txt:
Rate: AAAC
.....
我的shell脚本非常慢,因为它逐行读取文件,我该如何改进它。
INPUT=input.txt; key="Rate"
cat $INPUT | while read line
do
if [[ "$line" == *"$key"* ]]; then
name=`echo "$line" | cut -d" " -f2`
fi
echo "$line" >> "./tmp/$name"
done
答案 0 :(得分:2)
awk '/^Rate: / {
if (fn) close(fn)
fn = $2 ".txt"
}
{ print > fn }' infile
校正。
编辑:假设temp_dir存在(参见下面的评论):
awk '/^Rate: / {
if (fn) close(fn)
fn = "temp_dir/" $2 ".txt"
}
{ print > fn }' infile
答案 1 :(得分:1)
您的进程不是很慢,因为它逐行读取文件,但因为它每行产生两个进程。以不同的方式拆分工作,你会没事的。例如,有一个进程来识别“Rate”行,每个进程一个进程应该大大加快速度:
for rate in $( sed -n 's/^Rate: \(.*\)/\1/p' $INPUT )
do
sed -n "/^Rate: $rate\$/,/^Rate/ {/^Rate: / {/$rate/!d}; p}" $INPUT >$rate.txt
done
允许自己使用实际的脚本语言(或者使用bash保留它,但不再生成任何子进程),只允许遍历文件一次。例如,在纯粹的bash中,这应该削减它:
file=/dev/null
while read line
do
rate=${line#Rate: }
if [[ $line != $rate ]]; then file=$rate.txt
else echo "$line" >> $file; fi
done <$INPUT
答案 2 :(得分:0)
我认为问题的一部分是每一行都涉及执行echo
和cut
命令:
name=`echo "$line" | cut -d" " -f2`
(至少,我认为echo
调用的是/bin/echo
命令,而不是内置echo
的shell。我知道 {{1}有一个外部程序。)
此外,目标文件被重新打开并重新关闭(并且在没有通常的C标准IO缓冲的情况下写入,除非这些行巨大)用于每一行。< / p>
切换为另一种语言,让您无需cut
,fork(2)
,execve(2)
,open(2)
和write(2)
即可为每一行执行这些操作会有所改善。这是我在Ruby中的镜头:
close(2)
我在你提供的玩具输入上进行了测试,它似乎完全正确。