
그래서 개인적 및 학습 경험상의 이유로 날씨 데이터를 데이터베이스화하기 시작했습니다. 저는 wgrib2를 사용하여 데이터를 구문 분석하고 MySQL로 가져오고 있습니다. 데이터가 바람 "U" 및 "V" 구성 요소, 켈빈 등 다양한 단위로 형식화되어 있기 때문에 풍속 매듭, 풍속 반경, 온도 섭씨 등으로 변환해야 합니다.
모든 데이터 값을 반복하는 bash for 루프를 구성했지만 이는 다소 비효율적이며 이를 수행하는 더 좋은 방법이 있다고 확신합니다. awk에 많이 의존하며 약 1150개 스테이션에 대한 데이터를 구문 분석하는 데 15-17분이 소요됩니다. 각 스테이션에는 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
배열은 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