
Entonces, por razones personales y de experiencia de aprendizaje, comencé a realizar una base de datos de datos meteorológicos. Estoy usando wgrib2 para analizar los datos y importarlos a MySQL. Debido a que los datos están formateados en diferentes unidades: componentes de viento "U" y "V", kelvin, etc. Tengo que convertirlos a nudos de velocidad del viento, grados de viento, radio y grados de temperatura C... etc.
Construí un bucle bash for que recorre todos los valores de datos, pero es bastante ineficiente y estoy seguro de que hay mejores formas de hacerlo. Depende mucho de awk... y tarda entre 15 y 17 minutos analizar los datos de aproximadamente 1150 estaciones, cada estación tiene una tabla con una estructura idéntica con 160 columnas en la base de datos MySQL.
Las matrices bash que he configurado para TK (temperatura kelvin), RH (humedad), etc... tienen valores para 1000, 975, 950, 925... etc hasta 100 milibares.
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
Como puede ver con esto, el problema obvio es que realiza alrededor de 1150 * 160 llamadas a awk... así que probablemente pase las matrices maestras a awk y solo genere awk una vez por ciclo (¡1/160 de lo que estoy haciendo ahora!) sería más eficiente. Pero parece que no puedo entender bien la sintaxis de awk para esta práctica...
awk --version
GNU Awk 4.1.3, API: 1.1 (GNU MPFR 3.1.4, GNU MP 6.1.0)
He aquí un ejemplo:
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
^ esto no está bien. La matriz tiene 4 valores, no debería devolver solo 2.
echo -| awk -v tk="${TK[*]}" '{split(tk,tka,/ /)} { for (i=0; i<=length(tka); i++) { printf "%.1f\n", tka[i]-273.15 } } '
^ esto genera un bucle infinito.
¿Algunas ideas? ¿Quizás aprender algo de Perl y pasar todo esto a un script en Perl?
Respuesta1
Personalmente, sí, lo haría todo en Perl. :-)
TK=(325,350,231,655)
Ups. Cuidado. Ha creado una matriz de un solo elemento con una cadena separada por comas como elemento.
echo -| awk -v tk="${TK[*]}" '{split(tk,tka,/ /)} { for (i=0; i<=NF; i++) { printf "%.1f\n", tka[i]-273.15 } } '
awk
Las matrices comienzan en 1, no en cero.
Debido a que asigna la variable, en realidad no está utilizando los datos STDIN para nada más que el valor NF (pero ha pasado solo un elemento). En lugar de usar NF, contemos el resultado split
explícitamente. Quizás algo como esto:
$ 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
Como menciona dave_thompson_085, estás haciendo una especie de trabajo adicional al asignar los datos a una variable directamente en lugar de simplemente enviarlos a través de STDIN. Lo más común probablemente sería algo como:
$ echo ${TK[*]} | awk '{for (i=1; i<=NF; i++) { printf "%.1f\n", $i-273.15 } } '
51.9
76.9
-42.1
381.9
Y si quisiera comenzar con una perl
solución:
$ echo ${TK[*]} | perl -lane 'for $item (@F) {print $item-273.15}'
51.85
76.85
-42.15
381.85