Linux, macOSでPython, Ruby, Node.js, PHP, Apache, WordPress, jQueryの最新バージョン・ローカルバージョンを一括で取得・確認・比較するシェルスクリプト(バッチ処理プログラム) ~リリースバージョンとインストールされているバージョンの定期的なチェックで更新・アップデート対策~

2月 20, 2017AWS,EC2,jQuery,Node.js,PHP,Programming,Python,Ruby,Shell Script

システム運用において、使用しているソフトウェアのバージョン管理は非常に重要なタスクです。特にセキュリティパッチや機能改善が含まれる最新バージョンのリリース情報を定期的にチェックすることで、システムの安全性と安定性を保つことができます。

以前の記事「pyenv、rbenv、ndenvをシステム全体・システムワイドにインストールし、Python、Ruby、Node.jsのバージョンを使い分ける 〜Amazon Linux、CentOSで実行できる最新バージョンをインストールするシェルスクリプト(バッチ処理プログラム)〜」では、Python、Ruby、Node.jsの環境構築とバージョン管理について紹介しました。

本記事では、その続編として、複数のプログラミング言語やミドルウェアの最新バージョン情報を効率的に収集・確認するシェルスクリプトを紹介します。このスクリプトを使用することで、以下のような運用上のメリットが得られます:

  • セキュリティ脆弱性への迅速な対応
  • 新機能の適時な導入
  • バージョン管理の効率化
  • 定期的なチェック作業の自動化

対象ソフトウェアとバージョン管理の重要性

本スクリプトでは、Web開発で頻繁に使用される以下のソフトウェアを対象としています:

プログラミング言語

  • Python:データサイエンス、機械学習、Web開発など幅広く使用
  • Ruby:Ruby on Railsなどのフレームワークで人気
  • Node.js:サーバーサイドJavaScriptの実行環境
  • PHP:WordPressをはじめとするCMSで広く採用

ミドルウェア・ライブラリ

  • Apache HTTP Server:世界で最も使用されているWebサーバー
  • WordPress:世界シェアNo.1のCMS
  • jQuery:JavaScriptライブラリのデファクトスタンダード

これらのソフトウェアは定期的にアップデートがリリースされ、セキュリティパッチや新機能が追加されます。特にセキュリティ関連のアップデートを見逃すと、システムが攻撃のリスクにさらされる可能性があるため、定期的なバージョンチェックは必須です。

バージョン確認シェルスクリプトの実装

スクリプトの設計思想

このスクリプトは以下の設計方針に基づいて実装されています:

  1. 公式ソースからの情報取得:各ソフトウェアの公式サイトやミラーサイトから直接バージョン情報を取得
  2. 正規表現による柔軟なパース:HTMLからバージョン番号を正確に抽出
  3. クロスプラットフォーム対応:LinuxとmacOSの両方で動作
  4. ローカルバージョンとの比較:インストール済みバージョンと最新バージョンを並べて表示

完全版シェルスクリプト

以下が実際に動作するシェルスクリプトです。各セクションには詳細なコメントを付けています:

[magtranetwork@localhost ~]# vim check_new_version.sh
#!/bin/bash

#===============================================================================
# スクリプト名: check_new_version.sh
# 説明: 主要なプログラミング言語・ミドルウェアの最新バージョンをチェック
# 対応環境: Linux, macOS
# 対象ソフトウェア: Python, Ruby, Node.js, PHP, Apache, WordPress, jQuery
#===============================================================================

#-------------------------------------------------------------------------------
# バージョン抽出の基本ロジック
#-------------------------------------------------------------------------------
# 各リリースサイトのHTMLから、以下の処理フローでバージョンを抽出します:
#
# 1. バージョンを含む行を取得
# 2. 数値とドット以外を改行に置換(sed 's/[^0-9.]/'$LF'/g')
# 3. 数値で始まる行のみ抽出(grep '^[0-9]')
# 4. 先頭・末尾のドットを削除(sed 's/^\.//g' と sed 's/\.$//g')
# 5. 重複を削除(sort -n | uniq)
# 6. バージョン形式に一致するものを抽出
#
# 例:
#   X.Y 形式: grep '^[0-9]*\.[0-9]*$'
#   X.Y.Z 形式: grep '^[0-9]*\.[0-9]*\.[0-9]*$'
#   両方: grep -e '^[0-9]*\.[0-9]*\.[0-9]*$' -e '^[0-9]*\.[0-9]*$'
#-------------------------------------------------------------------------------

# 改行コードの定義(Linux/macOS両対応)
LF=$'\\\x0A'

#===============================================================================
# Python バージョンチェック
#===============================================================================
echo "======================================"
echo "Python"
echo "======================================"

# pythonコマンドの存在確認
which python > /dev/null 2>&1
IS_PKG=$?
IS_PKG=`echo "${IS_PKG}" | sed 's/ //g' | sed 's/\t//g' | tr -d '\n'`

echo "[Released Versions]"
# Python 3系の最新バージョン取得
PYTHON3_LATEST=`curl -sS https://www.python.org/downloads/ | \
  grep "Download Python " | grep '\.tar' | \
  sed 's/[^0-9.]/'$LF'/g' | grep '^[0-9]' | \
  sed 's/^\.//g' | sed 's/\.$//g' | \
  sort -n | uniq | \
  grep '^[0-9]*\.[0-9]*\.[0-9]*$' | grep ^3 | tail -n 1`
echo "  Python 3.x: ${PYTHON3_LATEST}"

# Python 2系の最新バージョン取得(メンテナンス終了に注意)
PYTHON2_LATEST=`curl -sS https://www.python.org/downloads/ | \
  grep "Download Python " | grep '\.tar' | \
  sed 's/[^0-9.]/'$LF'/g' | grep '^[0-9]' | \
  sed 's/^\.//g' | sed 's/\.$//g' | \
  sort -n | uniq | \
  grep '^[0-9]*\.[0-9]*\.[0-9]*$' | grep ^2 | tail -n 1`
echo "  Python 2.x: ${PYTHON2_LATEST} (※2020年にサポート終了)"

echo ""
echo "[Local Version]"
if [ "${IS_PKG}" = "0" ]; then
  python --version
else
  echo "  Python is not installed"
fi
echo ""

#===============================================================================
# Ruby バージョンチェック
#===============================================================================
echo "======================================"
echo "Ruby"
echo "======================================"

which ruby > /dev/null 2>&1
IS_PKG=$?
IS_PKG=`echo "${IS_PKG}" | sed 's/ //g' | sed 's/\t//g' | tr -d '\n'`

echo "[Released Versions]"
# RC版やpreview版を除外して安定版のみ取得
RUBY_LATEST=`curl -sS https://www.ruby-lang.org/en/downloads/ | \
  grep "Ruby" | grep '\.tar' | \
  grep -v '\-rc' | grep -v 'preview' | \
  sed 's/[^0-9.]/'$LF'/g' | grep '^[0-9]' | \
  sed 's/^\.//g' | sed 's/\.$//g' | \
  sort -n | uniq | \
  grep '^[0-9]*\.[0-9]*\.[0-9]*$' | tail -n 1`
echo "  Ruby: ${RUBY_LATEST}"

echo ""
echo "[Local Version]"
if [ "${IS_PKG}" = "0" ]; then
  ruby -v
else
  echo "  Ruby is not installed"
fi
echo ""

#===============================================================================
# Node.js バージョンチェック
#===============================================================================
echo "======================================"
echo "Node.js"
echo "======================================"

which node > /dev/null 2>&1
IS_PKG=$?
IS_PKG=`echo "${IS_PKG}" | sed 's/ //g' | sed 's/\t//g' | tr -d '\n'`

echo "[Released Versions]"
# Current版(最新機能を含むバージョン)
NODE_CURRENT=`curl -sS https://nodejs.org/en/download/current/ | \
  grep "Version" | grep "Latest" | grep "Current" | \
  sed 's/ //g' | sed 's// /g' | sed 's/<\/strong>/ /g' | \
  awk '{print $2}'`
echo "  Node.js Current: ${NODE_CURRENT} (最新機能版)"

# LTS版(長期サポート版)
NODE_LTS=`curl -sS https://nodejs.org/en/download/ | \
  grep "Version" | grep "Latest" | grep "LTS" | \
  sed 's/ //g' | sed 's// /g' | sed 's/<\/strong>/ /g' | \
  awk '{print $2}'`
echo "  Node.js LTS: ${NODE_LTS} (推奨:本番環境向け)"

echo ""
echo "[Local Version]"
if [ "${IS_PKG}" = "0" ]; then
  node -v
else
  echo "  Node.js is not installed"
fi
echo ""

#===============================================================================
# PHP バージョンチェック
#===============================================================================
echo "======================================"
echo "PHP"
echo "======================================"

which php > /dev/null 2>&1
IS_PKG=$?
IS_PKG=`echo "${IS_PKG}" | sed 's/ //g' | sed 's/\t//g' | tr -d '\n'`

echo "[Released Versions]"
# GitHubのタグからRC版、beta版、alpha版を除外して取得
PHP_LATEST=`curl -sS https://github.com/php/php-src/ | \
  grep 'href' | \
  grep '/php/php-src/tree/php-[0-9]*\.[0-9]*\.[0-9]*"' | \
  grep -v 'RC' | grep -v 'beta' | grep -v 'alpha' | \
  sed 's/[^0-9.]/'$LF'/g' | grep '^[0-9]' | \
  sed 's/^\.//g' | sed 's/\.$//g' | \
  sort -n | uniq | \
  grep '^[0-9]*\.[0-9]*\.[0-9]*$' | tail -n 1`
echo "  PHP: ${PHP_LATEST}"

echo ""
echo "[Local Version]"
if [ "${IS_PKG}" = "0" ]; then
  php -v | head -n 1
else
  echo "  PHP is not installed"
fi
echo ""

#===============================================================================
# Apache HTTP Server バージョンチェック
#===============================================================================
echo "======================================"
echo "Apache HTTP Server"
echo "======================================"

# ダウンロードサイトの設定(環境に応じて変更可能)
# 日本の高速ミラーサイトを使用
HTTPD_REPO=https://ftp.jaist.ac.jp/pub/apache/httpd
APR_REPO=https://ftp.jaist.ac.jp/pub/apache/apr

which apachectl > /dev/null 2>&1
IS_PKG=$?
IS_PKG=`echo "${IS_PKG}" | sed 's/ //g' | sed 's/\t//g' | tr -d '\n'`

echo "[Released Versions]"

# HTTPD(Apache本体)
HTTPD_LATEST=`curl -sS ${HTTPD_REPO}/ | \
  grep tar.gz | grep href | grep httpd-2.4 | \
  sed 's/[^0-9.]/'$LF'/g' | grep '^[0-9]' | \
  sed 's/^\.//g' | sed 's/\.$//g' | \
  sort -n | uniq | \
  grep '^[0-9]*\.[0-9]*\.[0-9]*$' | tail -n 1`
echo "  HTTPD (Apache本体): ${HTTPD_LATEST}"

# APR(Apache Portable Runtime)
APR_LATEST=`curl -sS ${APR_REPO}/ | \
  grep tar.gz | grep href | grep apr-[0-9] | \
  sed 's/[^0-9.]/'$LF'/g' | grep '^[0-9]' | \
  sed 's/^\.//g' | sed 's/\.$//g' | \
  sort -n | uniq | \
  grep '^[0-9]*\.[0-9]*\.[0-9]*$' | tail -n 1`
echo "  APR: ${APR_LATEST}"

# APR-UTIL
APR_UTIL_LATEST=`curl -sS ${APR_REPO}/ | \
  grep tar.gz | grep href | grep apr-util-[0-9] | \
  sed 's/[^0-9.]/'$LF'/g' | grep '^[0-9]' | \
  sed 's/^\.//g' | sed 's/\.$//g' | \
  sort -n | uniq | \
  grep '^[0-9]*\.[0-9]*\.[0-9]*$' | tail -n 1`
echo "  APR-UTIL: ${APR_UTIL_LATEST}"

# APR-ICONV
APR_ICONV_LATEST=`curl -sS ${APR_REPO}/ | \
  grep tar.gz | grep href | grep apr-iconv-[0-9] | \
  sed 's/[^0-9.]/'$LF'/g' | grep '^[0-9]' | \
  sed 's/^\.//g' | sed 's/\.$//g' | \
  sort -n | uniq | \
  grep '^[0-9]*\.[0-9]*\.[0-9]*$' | tail -n 1`
echo "  APR-ICONV: ${APR_ICONV_LATEST}"

echo ""
echo "[Local Version]"
if [ "${IS_PKG}" = "0" ]; then
  apachectl -V | grep -E "Server version|Server built|APR"
else
  echo "  Apache is not installed"
fi
echo ""

#===============================================================================
# WordPress バージョンチェック
#===============================================================================
echo "======================================"
echo "WordPress"
echo "======================================"

# WordPressのインストールパス(環境に応じて変更)
WORDPRESS_PATH=/var/www/html/wp-includes/version.php

echo "[Released Versions]"
WP_LATEST=`curl -sS https://wordpress.org/download/ | \
  grep "Version" | \
  sed 's/[^0-9.]/'$LF'/g' | grep '^[0-9]' | \
  sed 's/^\.//g' | sed 's/\.$//g' | \
  sort -n | uniq | \
  grep -e '^[0-9]*\.[0-9]*\.[0-9]*$' -e '^[0-9]*\.[0-9]*$' | tail -n 1`
echo "  WordPress: ${WP_LATEST}"

echo ""
echo "[Local Version]"
if [ -f ${WORDPRESS_PATH} ]; then
  WP_LOCAL=`cat ${WORDPRESS_PATH} | grep '\$wp_version' | \
    sed 's/[^0-9.]/'$LF'/g' | grep '^[0-9]' | \
    sed 's/^\.//g' | sed 's/\.$//g' | \
    sort -n | uniq | \
    grep -e '^[0-9]*\.[0-9]*\.[0-9]*$' -e '^[0-9]*\.[0-9]*$'`
  echo "  WordPress: ${WP_LOCAL}"
else
  echo "  WordPress is not installed or path is incorrect"
  echo "  (Current path: ${WORDPRESS_PATH})"
fi
echo ""

#===============================================================================
# jQuery バージョンチェック
#===============================================================================
echo "======================================"
echo "jQuery"
echo "======================================"

# jQueryファイルのパス(環境に応じて変更)
JQUERY_PATH=/var/www/html/js/jquery.min.js

echo "[Released Versions]"

# jQuery 3.x系
JQUERY3_LATEST=`curl -sS https://code.jquery.com/ | \
  grep 'jquery-3.' | grep '.min.js' | \
  sed 's/[^0-9.]/'$LF'/g' | grep '^[0-9]' | \
  sed 's/^\.//g' | sed 's/\.$//g' | \
  sort -n | uniq | \
  grep '^[0-9]*\.[0-9]*\.[0-9]*$' | tail -n 1`
echo "  jQuery 3.x: ${JQUERY3_LATEST} (推奨:最新版)"

# jQuery 2.x系
JQUERY2_LATEST=`curl -sS https://code.jquery.com/ | \
  grep 'jquery-2.' | grep '.min.js' | \
  sed 's/[^0-9.]/'$LF'/g' | grep '^[0-9]' | \
  sed 's/^\.//g' | sed 's/\.$//g' | \
  sort -n | uniq | \
  grep '^[0-9]*\.[0-9]*\.[0-9]*$' | tail -n 1`
echo "  jQuery 2.x: ${JQUERY2_LATEST}"

# jQuery 1.x系
JQUERY1_LATEST=`curl -sS https://code.jquery.com/ | \
  grep 'jquery-1.' | grep '.min.js' | \
  sed 's/[^0-9.]/'$LF'/g' | grep '^[0-9]' | \
  sed 's/^\.//g' | sed 's/\.$//g' | \
  sort -n | uniq | \
  grep '^[0-9]*\.[0-9]*\.[0-9]*$' | tail -n 1`
echo "  jQuery 1.x: ${JQUERY1_LATEST} (※レガシーブラウザ対応)"

echo ""
echo "[Local Version]"
if [ -f ${JQUERY_PATH} ]; then
  JQUERY_LOCAL=`cat ${JQUERY_PATH} | awk 'NR==1 {print}' | \
    sed 's/[^0-9.]/'$LF'/g' | grep '^[0-9]' | \
    sed 's/^\.//g' | sed 's/\.$//g' | \
    sort -n | uniq | \
    grep -e '^[0-9]*\.[0-9]*\.[0-9]*$' -e '^[0-9]*\.[0-9]*$'`
  echo "  jQuery: ${JQUERY_LOCAL}"
else
  echo "  jQuery is not installed or path is incorrect"
  echo "  (Current path: ${JQUERY_PATH})"
fi
echo ""

echo "======================================"
echo "Version check completed!"
echo "======================================"

スクリプトの実行方法

スクリプトを実行する前に、実行権限を付与する必要があります:

# 実行権限の付与
[magtranetwork@localhost ~]# chmod 755 check_new_version.sh

# スクリプトの実行
[magtranetwork@localhost ~]# ./check_new_version.sh

実行結果の例

以下は実際の実行結果のサンプルです。リリースバージョンとローカルバージョンが並べて表示されるため、アップデートの必要性が一目で分かります:

======================================
Python
======================================
[Released Versions]
  Python 3.x: 3.11.5
  Python 2.x: 2.7.18 (※2020年にサポート終了)

[Local Version]
Python 3.10.8

======================================
Ruby
======================================
[Released Versions]
  Ruby: 3.2.2

[Local Version]
ruby 3.1.0p0 (2021-12-25 revision fb4df44d16) [x86_64-linux]

======================================
Node.js
======================================
[Released Versions]
  Node.js Current: v20.8.0 (最新機能版)
  Node.js LTS: v18.18.0 (推奨:本番環境向け)

[Local Version]
v18.17.1

======================================
PHP
======================================
[Released Versions]
  PHP: 8.2.11

[Local Version]
PHP 8.1.12 (cli) (built: Oct 28 2022 17:39:43) (NTS)

======================================
Apache HTTP Server
======================================
[Released Versions]
  HTTPD (Apache本体): 2.4.58
  APR: 1.7.4
  APR-UTIL: 1.6.3
  APR-ICONV: 1.2.2

[Local Version]
Server version: Apache/2.4.54 (Unix)
Server built:   Jul 20 2023 15:32:01
APR: 1.7.0
APR-UTIL: 1.6.1

======================================
WordPress
======================================
[Released Versions]
  WordPress: 6.3.2

[Local Version]
  WordPress: 6.2.2

======================================
jQuery
======================================
[Released Versions]
  jQuery 3.x: 3.7.1 (推奨:最新版)
  jQuery 2.x: 2.2.4
  jQuery 1.x: 1.12.4 (※レガシーブラウザ対応)

[Local Version]
  jQuery: 3.6.0

======================================
Version check completed!
======================================

スクリプトのカスタマイズ方法

環境に応じた設定変更

スクリプト内の以下の変数は、環境に応じて変更する必要があります:

WordPressのパス

# デフォルト設定
WORDPRESS_PATH=/var/www/html/wp-includes/version.php

# カスタムパスの例
WORDPRESS_PATH=/home/username/public_html/wp-includes/version.php

jQueryのパス

# デフォルト設定
JQUERY_PATH=/var/www/html/js/jquery.min.js

# カスタムパスの例
JQUERY_PATH=/home/username/public_html/assets/js/jquery.min.js

Apacheダウンロードサイト

# 日本のミラーサイト(デフォルト)
HTTPD_REPO=https://ftp.jaist.ac.jp/pub/apache/httpd
APR_REPO=https://ftp.jaist.ac.jp/pub/apache/apr

# 別のミラーサイトの例
HTTPD_REPO=https://ftp.riken.jp/net/apache/httpd
APR_REPO=https://ftp.riken.jp/net/apache/apr

追加ソフトウェアの監視

スクリプトに他のソフトウェアのチェック機能を追加することも可能です。基本的なパターンは同じです:

# 例:Nginxのバージョンチェックを追加
echo "======================================"
echo "Nginx"
echo "======================================"

which nginx > /dev/null 2>&1
IS_PKG=$?

echo "[Released Versions]"
NGINX_LATEST=`curl -sS https://nginx.org/en/download.html | \
  grep "Stable version" | \
  sed 's/[^0-9.]/'$LF'/g' | grep '^[0-9]' | \
  sed 's/^\.//g' | sed 's/\.$//g' | \
  sort -n | uniq | \
  grep '^[0-9]*\.[0-9]*\.[0-9]*$' | tail -n 1`
echo "  Nginx: ${NGINX_LATEST}"

echo ""
echo "[Local Version]"
if [ "${IS_PKG}" = "0" ]; then
  nginx -v 2>&1 | cut -d'/' -f2
else
  echo "  Nginx is not installed"
fi
echo ""

定期実行の設定(cron)

バージョンチェックを自動化するために、cronで定期実行する設定をお勧めします:

# crontabの編集
crontab -e

# 毎週月曜日の午前9時に実行し、結果をメールで通知
0 9 * * 1 /path/to/check_new_version.sh | mail -s "Weekly Version Check Report" admin@example.com

# 毎日午前3時に実行し、ログファイルに出力
0 3 * * * /path/to/check_new_version.sh >> /var/log/version_check.log 2>&1

運用上の注意点とベストプラクティス

バージョンアップ時の注意事項

  1. 互換性の確認:メジャーバージョンアップ時は、既存のコードやプラグインとの互換性を必ず確認してください
  2. ステージング環境でのテスト:本番環境に適用する前に、必ずステージング環境でテストを実施してください
  3. バックアップの取得:アップデート前には必ずデータベースとファイルのバックアップを取得してください
  4. 段階的なロールアウト:複数のサーバーがある場合は、段階的にアップデートを適用してください

セキュリティアップデートへの対応

セキュリティパッチがリリースされた場合は、以下の手順で速やかに対応してください:

  1. リリースノートで脆弱性の内容と影響範囲を確認
  2. 自社システムが影響を受けるか評価
  3. 優先度を決定(緊急度:高/中/低)
  4. テスト環境でパッチ適用をテスト
  5. 本番環境へ適用
  6. 動作確認とモニタリング

推奨される監視体制

  • 定期チェック:週次または月次でバージョン確認を実施
  • セキュリティアラート購読:各ソフトウェアの公式セキュリティメーリングリストに登録
  • 変更管理:アップデート履歴を記録し、問題発生時のロールバック計画を準備
  • チーム共有:バージョン情報をチーム内で定期的に共有

トラブルシューティング

よくある問題と解決方法

1. curlコマンドがタイムアウトする

# タイムアウト時間を延長
curl -sS --connect-timeout 30 --max-time 60 https://www.python.org/downloads/

2. プロキシ環境での実行

# スクリプト先頭に追加
export http_proxy=http://proxy.example.com:8080
export https_proxy=http://proxy.example.com:8080

3. バージョン番号が正しく取得できない

Webサイトの構造が変更された可能性があります。以下のコマンドで実際のHTML構造を確認してください:

curl -sS https://www.python.org/downloads/ | grep -i "download python"

まとめ

本記事で紹介したシェルスクリプトを活用することで、以下のメリットが得られます:

  • 複数のソフトウェアのバージョン管理を一括で効率化
  • セキュリティリスクの早期発見と対応
  • 手動チェックの工数削減
  • システムの安定性と安全性の向上

定期的なバージョンチェックは、セキュアで安定したシステム運用の基本です。このスクリプトをベースに、環境に合わせてカスタマイズし、運用に組み込んでください。

また、バージョン管理と合わせて、冒頭で紹介した「pyenv、rbenv、ndenvを用いた環境構築」も参考にしていただくことで、より効率的な開発・運用環境を構築できます。

Reference: Tech Blog citing related sources