BBC NewsのRSSフィードを取得するスクリプトを改修しました。

改修した点

  • -m フラグの処理:
    • 引数に -m が指定された場合、インタラクティブモード(対話式)の関数を呼び出します。
  • セクションの番号選択:
    • 統合された全セクションを1から順にナンバリングして表示し、ユーザーが数字で選べるようにしました。
  • 件数の入力:
    • デフォルト値を提示しつつ、エンターを押すだけでデフォルト値(3件)が適用される親切設計にしています。

改修版スクリプト

#!/bin/bash

# デフォルト値の設定
default_section="world"
default_count=3

# メインセクションのリスト
main_sections=("world" "uk" "business" "politics" "health" "education" "science_and_environment" "technology" "entertainment_and_arts")

# グローバルセクションのリスト
global_sections=("africa" "asia" "europe" "latin_america" "middle_east" "us_and_canada")

# 全セクションのリストを統合
all_sections=("${main_sections[@]}" "${global_sections[@]}")

# --- [新規] 対話式メニュー関数 ---
interactive_menu() {
    echo "=== BBC News RSS セクション選択 ==="
    # セクション一覧を番号付きで表示
    for i in "${!all_sections[@]}"; do
        printf "%2d) %s\n" "$((i+1))" "${all_sections[$i]}"
    done

    # セクションの入力受付
    while true; do
        read -p "セクションの番号を選択してください (1-${#all_sections[@]}): " sec_num
        if [[ "$sec_num" =~ ^[0-9]+$ ]] && [ "$sec_num" -ge 1 ] && [ "$sec_num" -le "${#all_sections[@]}" ]; then
            section="${all_sections[$((sec_num-1))]}"
            break
        else
            echo "無効な入力です。正しい番号を入力してください。"
        fi
    done

    # 件数の入力受付
    read -p "表示する件数を入力してください (デフォルト: ${default_count}): " input_count
    if [[ "$input_count" =~ ^[0-9]+$ ]] && [ "$input_count" -gt 0 ]; then
        count=$input_count
    else
        count=$default_count
    fi
    echo "--------------------------------------------------"
}

# --- 引数の処理 ---
if [[ "$1" == "-m" ]]; then
    # 対話モードの起動
    interactive_menu
elif [[ "$1" =~ ^[0-9]+$ ]]; then
    section=$default_section
    count=$1
else
    section=${1:-$default_section} # 引数1が指定されていない場合はデフォルト値を使用
    count=${2:-$default_count}     # 引数2が指定されていない場合はデフォルト値を使用
fi

# 引数の短縮形を対応する正式名に変換 (通常モード用)
case "$section" in
    "usa" | "n-usa") section="us_and_canada" ;;
    "me") section="middle_east" ;;
    "latam" | "la") section="latin_america" ;;
    "eu") section="europe" ;;
    "science") section="science_and_environment" ;;
    "entertainment") section="entertainment_and_arts" ;;
    *) section=$section ;; # その他はそのまま
esac

# セクションの検証
if [[ ! " ${all_sections[@]} " =~ " ${section} " ]]; then
    echo "Error: Invalid section '${section}'. Valid sections are: ${all_sections[*]}"
    exit 1
fi

# URLの構築
if [[ " ${main_sections[@]} " =~ " ${section} " ]]; then
    url="https://feeds.bbci.co.uk/news/${section}/rss.xml"
else
    url="https://feeds.bbci.co.uk/news/world/${section}/rss.xml"
fi

# 最初に一度だけRSSフィードをダウンロードし、変数に格納する
xml_content=$(curl -s "$url")

# コンテンツが取得できなかった場合はエラー終了
if [ -z "$xml_content" ]; then
    echo "Error: No headlines found for section '${section}'. Please check the section name or try again later."
    exit 1
fi

# フィードの最終更新日時を取得し、フォーマットする
feed_date_raw=$(echo "$xml_content" | xmllint --xpath "string(//channel/lastBuildDate)" - 2>/dev/null)
if [ -n "$feed_date_raw" ]; then
    # JSTに変換して表示フォーマットを整える
    feed_date_formatted=$(date -d "$feed_date_raw" '+%Y/%m/%d %H:%M:%S %Z')
fi

# 見出しを取得
headlines=$(echo "$xml_content" | xmllint --xpath "//item/title/text()" - 2>/dev/null | sed -e 's/<!\[CDATA\[//g' -e 's/\]\]>//g' | head -n "$count")

# 見出しの表示
echo "BBC News - ${section} section (${count} headlines)"
# 取得した日付を表示
if [ -n "$feed_date_formatted" ]; then
    echo "As of: ${feed_date_formatted}"
fi
echo "--------------------------------------------------" #区切り線
echo "$headlines"

使い方

  1. 通常モード(従来通り)

引数をそのまま渡せば、セクションごとに件数を表示してくれます。

./bbc_headline.sh business 5
  1. 対話式メニューモード(新機能)

-m を付けて実行します。

./bbc_headline.sh -m

実行イメージ:

=== BBC News RSS セクション選択 ==
 1) world
 2) uk
...
15) us_and_canada
セクションの番号を選択してください (1-15): 3
表示する件数を入力してください (デフォルト: 3): 5
--------------------------------------------------
BBC News - business section (5 headlines)
...

graph TD A("スクリプト開始") --> B{"引数の判定"} %% 引数の分岐 B -->|"-m"| C["対話式メニュー関数 interactive_menu"] B -->|"数字"| D["セクション: デフォルト<br>件数: 引数1の数字"] B -->|"その他"| E["セクション: 引数1<br>件数: 引数2"] %% 対話モードの詳細 subgraph "対話モードの内部処理" C --> C1["セクション一覧を番号付きで表示"] C1 --> C2["ユーザーが番号を入力"] C2 --> C3{"有効な番号か?"} C3 -->|"No"| C2 C3 -->|"Yes"| C4["セクション名を確定"] C4 --> C5["ユーザーが表示件数を入力"] C5 --> C6{"数字が入力されたか?"} C6 -->|"Yes"| C7["入力された件数を採用"] C6 -->|"No"| C8["デフォルトの3件を採用"] end %% 合流後の共通処理 C7 --> F["短縮名の変換ケース文"] C8 --> F D --> F E --> F F --> G{"有効なセクション名か?"} G -->|"No"| H("エラーを表示して終了") G -->|"Yes"| I{"メインかグローバルか?"} %% URL構築 I -->|"メイン"| J["URL: news/セクション/rss.xml"] I -->|"グローバル"| K["URL: news/world/セクション/rss.xml"] %% 取得と出力 J --> L["curl で RSS XML をダウンロード"] K --> L L --> M{"データが空でないか?"} M -->|"No"| N("エラーを表示して終了") M -->|"Yes"| O["xmllint で最終更新日時を取得・JST変換"] O --> P["xmllint と head で見出しを抽出"] P --> Q["結果を画面に出力"] Q --> R("スクリプト終了") %% スタイルの調整 style C fill:#f9f,stroke:#333,stroke-width:2px style C1 fill:#fff2cc,stroke:#d6b656 style C2 fill:#fff2cc,stroke:#d6b656 style C5 fill:#fff2cc,stroke:#d6b656

このスクリプトは役に立つのか?

私が便利だと思ったから乗せています。実際、/etc/update-motdに仕込むことで、「今はこういう出来事が起こっている」をリアルタイムで知ることができるからです。