因此,出于个人和学习经验的原因,我开始将天气数据数据库化。我正在使用 wgrib2 解析数据,并导入到 MySQL。因为数据采用不同的单位格式 - 风“U”和“V”分量、开尔文等...我必须将其转换为风速节、风度半径和温度摄氏度...等。
我构建了一个 bash for 循环来循环遍历所有数据值,但效率很低,我相信有更好的方法可以做到这一点。它非常依赖 awk... 并且需要 15-17 分钟来解析大约 1150 个车站的数据,每个车站在 MySQL 数据库中都有一个结构完全相同的表,其中包含 160 列。
我为 TK(温度开尔文)、RH(湿度)等设置的 bash 数组...具有 1000、975、950、925...等一直到 100 毫巴的值。
for thKey in ${!TK[@]}
do
thRH=${RH[$thKey]}
thTK=${TK[$thKey]}
thTC=$(echo -| awk -v tk="$thTK" '{printf "%.1f\n", tk-273.15}')
thWU=${WU[$thKey]}
thWV=${WV[$thKey]}
thTD=$(echo -| awk -v tc="$thTC" -v rh="$thRH" '{printf "%.1f\n", tc-(100-rh)/5}')
thWD=$(echo -| awk -v wu="$thWU" -v wv="$thWV" '{printf "%.0f\n", 57.29578*(atan2(wu, wv))+180}')
thWS=$(echo -| awk -v wu="$thWU" -v wv="$thWV" '{printf "%.1f\n", sqrt(wu*wu+wv*wv)*1.944}')
sed -i '/\/station_id/a <'"$thKey"'T>'"$thTC"'<\/'"$thKey"'T><'"$thKey"'D>'"$thTD"'<\/'"$thKey"'D><'"$thKey"'WD>'"$thWD"'<\/'"$thKey"'WD><'"$thKey"'WS>'"$thWS"'<\/'"$thKey"'WS>' $xmlOut
done
正如你所看到的,明显的问题是它对 awk 进行了大约 1150 * 160 次调用...所以可能将主数组传递给 awk 并且每个循环只生成 awk 一次(我现在正在做的事情的 1/160!)会更有效率。但我似乎无法获得适合这种做法的 awk 语法......
awk --version
GNU Awk 4.1.3,API:1.1(GNU MPFR 3.1.4,GNU MP 6.1.0)
这是一个例子:
TK=(325,350,231,655)
echo -| awk -v tk="${TK[*]}" '{split(tk,tka,/ /)} { for (i=0; i<=NF; i++) { printf "%.1f\n", tka[i]-273.15 } } '
-273.1 51.9
^ 这是不对的。该数组有 4 个值,它不应该只返回 2 个。
echo -| awk -v tk="${TK[*]}" '{split(tk,tka,/ /)} { for (i=0; i<=length(tka); i++) { printf "%.1f\n", tka[i]-273.15 } } '
^ 这会产生无限循环。
有任何想法吗?也许学习一些 Perl 并将所有这些传递给 Perl 脚本?
答案1
就我个人而言,是的,我会用 Perl 来完成这一切。 :-)
TK=(325,350,231,655)
哎呀。小心。您已经创建了一个单元素数组,其中以逗号分隔的字符串作为元素。
echo -| awk -v tk="${TK[*]}" '{split(tk,tka,/ /)} { for (i=0; i<=NF; i++) { printf "%.1f\n", tka[i]-273.15 } } '
awk
数组从 1 开始,而不是从零开始。
因为您分配了变量,所以您实际上并没有将 STDIN 数据用于除 NF 值之外的任何内容(但您只传入了一个元素)。我们不使用 NF,而是显式地计算结果split
。也许是这样的:
$ TK=(325 350 231 655)
$ echo - | awk -v tk="${TK[*]}" '{fields=split(tk,tka,/ /)} { for (i=1; i<=fields; i++) { printf "%.1f\n", tka[i]-273.15 } } '
51.9
76.9
-42.1
381.9
正如 dave_thompson_085 提到的,您通过直接将数据分配给变量而不是仅仅通过 STDIN 发送它来完成额外的工作。更常见的可能是这样的:
$ echo ${TK[*]} | awk '{for (i=1; i<=NF; i++) { printf "%.1f\n", $i-273.15 } } '
51.9
76.9
-42.1
381.9
如果您确实想要开始解决perl
方案:
$ echo ${TK[*]} | perl -lane 'for $item (@F) {print $item-273.15}'
51.85
76.85
-42.15
381.85