【发布时间】:2021-03-09 09:58:57
【问题描述】:
我正在解析一个 18GB 文件 summarize_eigenvectors.out 中的信息,该文件具有以下结构:
Special analysis for state 3293 3.56009
c v weight ik kx ky kz
1 1 0.00000 1 0.00000 0.00000 0.00000
1 1 0.00000 2 0.00000 0.04167 0.00000
1 2 0.00000 1 0.00000 0.00000 0.00000
1 2 0.00000 2 0.00000 0.04167 0.00000
2 1 0.00000 1 0.00000 0.00000 0.00000
2 1 0.00000 2 0.00000 0.04167 0.00000
2 2 0.00000 1 0.00000 0.00000 0.00000
2 2 0.00000 2 0.00000 0.04167 0.00000
Special analysis for state 3294 3.56013
c v weight ik kx ky kz
1 1 0.00000 1 0.00000 0.00000 0.00000
1 1 0.00000 2 0.00000 0.04167 0.00000
1 2 0.00000 1 0.00000 0.00000 0.00000
1 2 0.00000 2 0.00000 0.04167 0.00000
2 1 0.00000 1 0.00000 0.00000 0.00000
2 1 0.00000 2 0.00000 0.04167 0.00000
2 2 0.00000 1 0.00000 0.00000 0.00000
2 2 0.00000 2 0.00000 0.04167 0.00000
在实际系统中,索引上升到
12 12 0.00000 1152 0.00000 0.00000 0.00000
我正在使用 egrep 将大文件的每个部分解析为较小的文件。另一个文件 summarize_eigenvectors_range.in 包含以下内容:
1870 #total number of excitons to analyze
0.35600872E+01
0.35601277E+01
0.35603700E+01
....
主要脚本如下:
#!/bin/bash
P=`pwd`
#if [ -d summarize_eigenvectors ]; then
# rm -r summarize_eigenvectors
# mkdir summarize_eigenvectors
# cd summarize_eigenvectors
#else
# mkdir summarize_eigenvectors
cd summarize_eigenvectors
#fi
number=$(awk 'NR==1''{ print$1 }' ../summarize_eigenvectors_range.in)
line=$(( $number + 1 ))
i=2
#start_id=$(grep -m 1 "Special analysis for state" ../summarize_eigenvectors.out | awk '{ print$5 }')
start_id=4137
echo start_id = $start_id
while [ $i -le $line ]
do
exciton_n=$(awk -v i="$i" 'NR==i''{ print$1 }' ../summarize_eigenvectors_range.in)
nstring=$(echo $exciton_n | awk -F"E" 'BEGIN{OFMT="%10.5f"} {print $1 * (10 ^ $2)}')
nid=$(( $start_id + $i - 2 ))
name=`echo "$nid"_"$nstring" | sed -e 's/[[:space:]]//g'`
echo "$name"
mkdir "$name"
cd "$name"
mkdir sorted
egrep -A 165889 "Special analysis for state.*$nid" ../../summarize_eigenvectors.out > $name.txt
for c in $(seq 1 12); do
for v in $(seq 1 12); do
echo -e " c v weight ik kx ky kz" > "$name"-"$c"_"$v".txt
awk -v c="$c" -v v="$v" '{ if ($1 == c && $2 == v) print }' $name.txt >> "$name"-"$c"_"$v".txt
cat "$name"-"$c"_"$v".txt | sort -k 3 -g -r > ./sorted/"$name"-"$c"_"$v"-sorted.txt
done
done
cd ..
i=$(( $i + 1 ))
done
此操作每个部分大约需要 30 秒,而我有数千个这样的部分。有没有更好的方法可以让脚本运行得更快?我正在考虑使用awk,但不知道如何将字符串和变量的搜索结合在一起;也不知道会不会有更好的表现。
关于性能瓶颈在哪里的任何见解以及关于如何改进代码的任何建议?
示例输出: 几千个文件,一种类型包含“特别分析”部分中的所有内容,内容如下:
Special analysis for state {nid} x.xxxxx
c v weight ik kx ky kz
1 1 0.00000 1 0.00000 0.00000 0.00000
....
12 12 0.00000 1152 0.00000 0.00000 0.00000
另一种将上述文件分为c1v1 c1v2等c1v1文件如下所示
c v weight ik kx ky kz
1 1 0.00000 1 0.00000 0.00000 0.00000
1 1 0.00000 2 0.00000 0.00000 0.00000
....
1 1 0.00000 1152 0.00000 0.00000 0.00000
c1v2 文件如下所示
c v weight ik kx ky kz
2 2 0.00000 1 0.00000 0.00000 0.00000
2 2 0.00000 2 0.00000 0.00000 0.00000
....
2 2 0.00000 1152 0.00000 0.00000 0.00000
【问题讨论】:
-
请发布具有预期输出的可测试样本。
-
需要更多详细信息,例如,
$line是什么,对您正在做的事情的简要文字说明(将 1154 行的块解析为单独的文件?),也许还有一些示例输入行前 2 个部分,以及与样本输入对应的所需输出;话虽如此,我猜整个事情可以用awk和单次遍历文件来完成(而不是你目前通过文件进行的数千次遍历) -
@Jacek :我看不到您在脚本中设置
line的位置,但无论如何,您为循环中的每个迭代创建一个子进程,并且这些子进程中的每一个都有从头到尾依次遍历大文件。也许您可以考虑重新设计您的文章,以便它只需要一次文件传递。您只需要一个“缓冲区”来保存比赛前后的 1153 行,以创建不同的输出文件。 -
当我看到有人知道使用
$(...)但只对某些行使用的代码时,我总是感到困惑,例如start_id=$(...)但name=`...`仅在 5 行之后。