
Portanto, por motivos de experiência pessoal e de aprendizagem, comecei a basear dados meteorológicos. Estou usando o wgrib2 para analisar os dados e importar para o MySQL. Como os dados são formatados em unidades diferentes - componentes "U" e "V" do vento, kelvin, etc... Tenho que convertê-los em nós de velocidade do vento, graus de raio do vento e graus C de temperatura... etc.
Eu construí um loop for bash que percorre todos os valores de dados, mas é bastante ineficiente e tenho certeza de que há maneiras melhores de fazer isso. Ele depende do awk, muito ... e leva de 15 a 17 minutos para analisar dados de cerca de 1150 estações, cada estação possui uma tabela com estrutura idêntica com 160 colunas no banco de dados MySQL.
As matrizes bash que configurei para TK (temperatura Kelvin), RH (umidade), etc... têm valores para 1000, 975, 950, 925... etc até 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 você pode ver, o problema óbvio é que ele faz cerca de 1150 * 160 chamadas para o awk... então, provavelmente, passar os arrays mestres para o awk e gerar o awk apenas uma vez por loop (1/160 do que estou fazendo agora!) seria mais eficiente. Mas não consigo acertar a sintaxe do awk para esta prática ...
awk --version
GNU Awk 4.1.3, API: 1.1 (GNU MPFR 3.1.4, GNU MP 6.1.0)
Aqui está um exemplo:
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
^ isso não está certo. O array possui 4 valores, não deve retornar apenas 2.
echo -| awk -v tk="${TK[*]}" '{split(tk,tka,/ /)} { for (i=0; i<=length(tka); i++) { printf "%.1f\n", tka[i]-273.15 } } '
^ isso gera um loop infinito.
Alguma ideia? Talvez aprender um pouco de perl e passar tudo isso para um script perl?
Responder1
Pessoalmente, sim, eu faria tudo em Perl. :-)
TK=(325,350,231,655)
Ops. atenção. Você criou uma matriz de elemento único com uma string separada por vírgula como elemento.
echo -| awk -v tk="${TK[*]}" '{split(tk,tka,/ /)} { for (i=0; i<=NF; i++) { printf "%.1f\n", tka[i]-273.15 } } '
awk
matrizes começam em 1, não em zero.
Como você atribui a variável, você não está realmente usando os dados STDIN para nada além do valor NF (mas você passou apenas um único elemento). Em vez de usar NF, vamos apenas contar o resultado explicitamente split
. Talvez algo assim:
$ 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 dave_thompson_085 menciona, você está fazendo um trabalho extra atribuindo os dados diretamente a uma variável, em vez de apenas enviá-los via STDIN. Mais comum provavelmente seria 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
E se você quiser começar uma perl
solução:
$ echo ${TK[*]} | perl -lane 'for $item (@F) {print $item-273.15}'
51.85
76.85
-42.15
381.85