
Поэтому для личного и учебного опыта я начал создавать базу данных погодных данных. Я использую wgrib2 для разбора данных и импорта в MySQL. Поскольку данные отформатированы в разных единицах - компоненты ветра "U" и "V", кельвины и т. д. Мне нужно преобразовать их в узлы скорости ветра, радиусы ветра и температуру в градусах Цельсия и т. д.
Я создал bash for loop, который перебирает все значения данных, но он довольно неэффективен, и я уверен, что есть лучшие способы сделать это. Он во многом опирается на awk... и занимает 15-17 минут, чтобы разобрать данные для примерно 1150 станций, каждая станция имеет таблицу с идентичной структурой и 160 столбцами в базе данных MySQL.
Массивы bash, которые я настроил для TK (температура по Кельвину), RH (влажность) и т. д., имеют значения 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
Как вы можете видеть, очевидная проблема в том, что он делает около 1150 * 160 вызовов awk... так что, вероятно, передача основных массивов в 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