以前作成したコマンドラインでの天気予報ツールについて改良を行いました。
修正前のスクリプト
まず、修正前のスクリプトはこちらです。
#!/bin/bash
# 都市名をコマンドライン引数から取得するか、ユーザーに尋ねる
city=$1
if [[ -z "$city" ]]; then
echo "都市名を入力してください:"
read city
if [[ -z "$city" ]]; then
echo "都市名が入力されませんでした。"
exit 1
fi
fi
# ansiweatherコマンドを実行して天気情報を表示
echo "ansiweatherの情報:"
if ! ansiweather -l "$city"; then
echo "ansiweatherから情報を取得できませんでした。"
fi
# curlコマンドを使用してwttr.inから天気情報を表示
echo "wttr.inの情報:"
if ! curl -s "wttr.in/${city}?lang=ja"; then
echo "wttr.inから情報を取得できませんでした。"
fi
このスクリプトは、コマンドライン引数で都市名を受け取るか、引数がなければユーザーに都市名の入力を求め、ansiweather
とcurl
を使って天気情報を取得し表示します。
問題点
- エラー処理が不十分: 都市名が入力されない場合のエラー処理はありますが、
ansiweather
やcurl
コマンドが失敗した場合の処理は警告メッセージを表示するだけです。 - 入力検証がない: 空白のみの入力など、不正な入力に対する検証が行われていません。
- 複数都市に対応していない: コマンドライン引数で複数の都市を指定することができません。
- コードの再利用性がない: 処理がまとまっていないため、コードの再利用が難しいです。
修正後のスクリプト
そこで、以下のように修正です。
#!/bin/bash
# 都市名を取得する関数
get_city() {
if [[ -z "$1" ]]; then
read -p "都市名を入力してください: " city
if [[ -z "$city" ]]; then
echo "エラー: 都市名が入力されていません。" >&2
return 1
fi
else
city="$1"
fi
# 入力値の検証
if [[ "$city" =~ ^[[:space:]]+$ ]]; then
echo "エラー: 都市名に空白のみが入力されています。" >&2
return 1
fi
return 0
}
# 天気情報を表示する関数
show_weather() {
local city="$1"
echo "--------------------"
echo "ansiweatherの情報 (${city}):"
if ! ansiweather -l "$city"; then
echo "警告: ansiweatherから情報を取得できませんでした。" >&2
fi
echo "--------------------"
echo "wttr.inの情報 (${city}):"
if ! curl -fs --connect-timeout 5 "wttr.in/${city}?lang=ja"; then
echo "警告: wttr.inから情報を取得できませんでした。" >&2
fi
}
# メイン処理
if [[ $# -eq 0 ]]; then
if ! get_city; then
exit 1
fi
show_weather "$city"
elif [[ $# -gt 0 ]]; then
for city in "$@"; do
if ! get_city "$city"; then
echo "$city の処理をスキップします。" >&2
continue
fi
show_weather "$city"
done
fi
exit 0
修正の意図と変更点
- 関数化:
get_city()
関数とshow_weather()
関数に処理を分割し、コードの可読性と再利用性を向上させました。 - エラー処理の改善:
get_city()
関数内で都市名が入力されない場合や空白のみが入力された場合にエラーメッセージを出力し、終了ステータスを返しています。エラーメッセージは標準エラー出力(>&2
)に出力することで、通常の出力と区別しています。show_weather()
関数内でansiweather
やcurl
コマンドが失敗した場合に警告メッセージを標準エラー出力に出力するように変更しました。- 入力検証の追加:
get_city()
関数内で空白のみの入力に対する検証を追加しました。 - 複数都市への対応: コマンドライン引数で複数の都市を指定できるように変更しました。
for
ループを使って、それぞれの都市に対して天気情報を取得し表示します。./script Narita London
とすることで、出発地と目的地の天気を同時に示すことができます。 curl
コマンドのオプション変更:curl -s
に加えて-f
(エラー時にHTTPステータスコードを返す)と--connect-timeout 5
(接続タイムアウトを5秒に設定)を追加し、より堅牢な処理を実現しました。
修正後に加わった挙動。
- コマンドライン引数で複数の都市を指定して実行できるようになりました。例:
./script.sh Osaka Kyoto
- 都市名が入力されない場合や空白のみが入力された場合、エラーメッセージが表示されるようになりました。
ansiweather
やcurl
コマンドが失敗した場合、警告メッセージが標準エラー出力に出力されるようになりました。curl
コマンドのタイムアウトが設定されたため、ネットワークの問題などで応答がない場合に処理が止まるのを防ぐことができます。