我有一个 200 MB 的制表符分隔文本文件,其中包含数百万行。在此文件中,我有一列包含多个位置,例如 US 、 UK 、 AU 等。
现在我想根据这个专栏来破解这个文件。虽然这段代码对我来说运行良好,但面临性能问题,因为根据位置将文件拆分为多个文件需要 1 个多小时。这是代码:
#!/bin/bash
read -p "Please enter the file to split " file
read -p "Enter the Col No. to split " col_no
#set -x
header=`head -1 $file`
cnt=1
while IFS= read -r line
do
if [ $((cnt++)) -eq 1 ]
then
echo "$line" >> /dev/null
else
loc=`echo "$line" | cut -f "$col_no"`
f_name=`echo "file_"$loc".txt"`
if [ -f "$f_name" ]
then
echo "$line" >> "$f_name";
else
touch "$f_name";
echo "file $f_name created.."
echo "$line" >> "$f_name";
sed -i '1i '"$header"'' "$f_name"
fi
fi
done < $file
这里应用的逻辑是,我们只读取整个文件一次,并且根据位置,我们创建数据并将其附加到其中。
请对代码提出必要的改进建议,以提高其性能。
以下是示例数据,并用冒号而不是制表符分隔。国家/地区代码位于第 4 列:
ID1:ID2:ID3:ID4:ID5
100:abcd:TEST1:ZA:CCD
200:abcd:TEST2:US:CCD
300:abcd:TEST3:AR:CCD
400:abcd:TEST4:BE:CCD
500:abcd:TEST5:CA:CCD
600:abcd:TEST6:DK:CCD
312:abcd:TEST65:ZA:CCD
1300:abcd:TEST4153:CA:CCD
最佳答案
有几点需要牢记:
- 使用
while read
读取文件速度很慢 - 创建子 shell 和执行外部进程很慢
这是文本处理工具的工作,例如 awk。
我建议你使用这样的东西:
# save first line
NR == 1 {
header = $0
next
}
{
filename = "file_" $col ".txt"
# if country code has changed
if (filename != prev) {
# close the previous file
close(prev)
# if we haven't seen this file yet
if (!(filename in seen)) {
print header > filename
}
seen[filename]
}
# print whole line to file
print >> filename
prev = filename
}
使用以下内容运行脚本:
awk -v col="$col_no" -f script.awk file
其中 $col_no
是一个 shell 变量,其中包含带有国家/地区代码的列号。
如果您没有太多不同的国家/地区代码,则可以将所有文件保持打开状态,在这种情况下,您可以删除对 close(filename)
的调用。
您可以在问题中提供的示例上测试脚本,如下所示:
awk -F: -v col=4 -f script.awk file
请注意,我添加了 -F:
将输入字段分隔符更改为 :
。
关于bash - shell脚本中的性能问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41238656/