그래서 개인적, 학습적 경험상의 이유로 날씨 데이터를 데이터베이스화하기 시작했습니다. 저는 wgrib2를 사용하여 데이터를 구문 분석하고 이를 MySQL로 가져옵니다. 데이터가 바람 "U" 및 "V" 구성요소, 켈빈 등 다양한 단위 형식을 갖고 있기 때문에 이를 풍속(노트), 풍도 반경, 온도(섭씨) 등으로 변환해야 합니다.
모든 데이터 값을 반복하기 위해 bash for 루프를 만들었지만 이는 매우 비효율적이며 이를 수행하는 더 좋은 방법이 있다고 확신합니다. 이는 awk에 크게 의존하며 약 1150개 스테이션의 데이터를 구문 분석하는 데 15~17분이 소요됩니다. 각 스테이션에는 160개 열이 있는 MySQL 데이터베이스에 동일하게 구조화된 테이블이 있습니다.
TK(켈빈 온도), RH(습도) 등에 대해 설정한 bash 배열의 값은 1000, 975, 950, 925... 등 최대 100mbar입니다.
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를 생성할 수 있습니다(지금 내가 하고 있는 작업 중 하나/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
배열은 0이 아닌 1부터 시작합니다.
변수를 할당했기 때문에 실제로 NF 값 외에는 STDIN 데이터를 사용하지 않았습니다(그러나 하나의 요소만 전달했습니다). 우리는 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