タグ: シェルスクリプト Page 1 of 6

Rubyスクリプト改修。(SSL証明書の有効期限確認)

SSL証明書の有効期限を確認するスクリプト、改修しました。

スクリプト内容

require 'openssl'
require 'socket'
require 'date'
require 'uri'
require 'timeout'

# ユーザーからURLを対話的に受け取る
def get_user_input
  print "チェックしたいサイトのドメインを入力してください(例: example.com): "
  domain = gets.chomp

  # 入力がhttp://またはhttps://で始まらない場合は、https://を追加
  domain = "https://#{domain}" unless domain.start_with?('http://', 'https://')
  
  domain
end

# 変数で指定したURLに接続して証明書の有効期限を取得するメソッド
def get_certificate_expiry_date(url)
  uri = URI.parse(url)
  hostname = uri.host
  ssl_socket = nil
  tcp_client = nil

  begin
    # タイムアウトを5秒に設定してSSL接続を確立
    Timeout.timeout(5) do
      tcp_client = TCPSocket.new(hostname, 443)
      ssl_context = OpenSSL::SSL::SSLContext.new
      ssl_socket = OpenSSL::SSL::SSLSocket.new(tcp_client, ssl_context)
      ssl_socket.hostname = hostname
      ssl_socket.connect

      # 証明書の有効期限を取得
      cert = ssl_socket.peer_cert
      expiration_date = DateTime.parse(cert.not_after.to_s)
      days_remaining = (expiration_date - DateTime.now).to_i

      return expiration_date, days_remaining
    end
  rescue Timeout::Error
    return nil, "サーバーへの接続がタイムアウトしました。"
  rescue => e
    return nil, e.to_s
  ensure
    ssl_socket&.close
    tcp_client&.close
  end
end

# メイン処理
def main
  # コマンドライン引数を確認
  url = if ARGV[0]
          # 引数でドメインが指定されている場合
          domain = ARGV[0]
          domain = "https://#{domain}" unless domain.start_with?('http://', 'https://')
          domain
        else
          # 対話的に入力を受け付ける
          get_user_input
        end

  expiration_date, days_remaining = get_certificate_expiry_date(url)

  if expiration_date
    formatted_date = expiration_date.strftime("%Y/%m/%d")
    puts "サイト #{url} の有効期限は #{formatted_date} です。残り #{days_remaining} 日です。"
  else
    puts "証明書の取得に失敗しました: #{days_remaining}"
  end
end

# メイン処理を呼び出し
main

改修内容

引数化したことです。

ruby ssl_checker.rb google.co.jp
サイト https://google.co.jp の有効期限は 2025/03/31 です。残り 61 日です。

と、スクリプトの後にドメイン指定で残り日数を示します。

ruby ssl_checker.rb
チェックしたいサイトのドメインを入力してください(例: example.com): google.co.jp
サイト https://google.co.jp の有効期限は 2025/03/31 です。残り 61 日です。

引数なしだと対話式に切り替わります。

これで、変数をハードコートする必要がなくなり、他のスクリプトにも組み込みやすくなりました。

シェルスクリプト天気予報ツールの改良:機能追加とエラー処理の強化

以前作成したコマンドラインでの天気予報ツールについて改良を行いました。

修正前のスクリプト

まず、修正前のスクリプトはこちらです。

#!/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

このスクリプトは、コマンドライン引数で都市名を受け取るか、引数がなければユーザーに都市名の入力を求め、ansiweathercurlを使って天気情報を取得し表示します。

問題点

  • エラー処理が不十分: 都市名が入力されない場合のエラー処理はありますが、ansiweathercurlコマンドが失敗した場合の処理は警告メッセージを表示するだけです。
  • 入力検証がない: 空白のみの入力など、不正な入力に対する検証が行われていません。
  • 複数都市に対応していない: コマンドライン引数で複数の都市を指定することができません。
  • コードの再利用性がない: 処理がまとまっていないため、コードの再利用が難しいです。

修正後のスクリプト

そこで、以下のように修正です。

#!/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()関数内でansiweathercurlコマンドが失敗した場合に警告メッセージを標準エラー出力に出力するように変更しました。
  • 入力検証の追加: get_city()関数内で空白のみの入力に対する検証を追加しました。
  • 複数都市への対応: コマンドライン引数で複数の都市を指定できるように変更しました。forループを使って、それぞれの都市に対して天気情報を取得し表示します。
    ./script Narita Londonとすることで、出発地と目的地の天気を同時に示すことができます。
  • curlコマンドのオプション変更: curl -sに加えて-f(エラー時にHTTPステータスコードを返す)と--connect-timeout 5(接続タイムアウトを5秒に設定)を追加し、より堅牢な処理を実現しました。

修正後に加わった挙動。

  • コマンドライン引数で複数の都市を指定して実行できるようになりました。例:./script.sh Osaka Kyoto
  • 都市名が入力されない場合や空白のみが入力された場合、エラーメッセージが表示されるようになりました。
  • ansiweathercurlコマンドが失敗した場合、警告メッセージが標準エラー出力に出力されるようになりました。
  • curlコマンドのタイムアウトが設定されたため、ネットワークの問題などで応答がない場合に処理が止まるのを防ぐことができます。

BBC Newsの見出しを取得するBashスクリプト、更に改良

これを更に改良です。

スクリプト

  • bbc_headlin.sh
#!/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[@]}")

# 引数の処理
if [[ "$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

# BBC NewsのRSSフィードから見出しを取得
headlines=$(curl -s "$url" | xmllint --format - | grep -oP '(?<=<title>).*?(?=</title>)' | sed -n '3,'"$((count+2))"'p' | sed 's/<!\[CDATA\[//g' | sed 's/\]\]>//g')

# 見出しの表示
if [ -z "$headlines" ]; then
echo "No headlines found for section '${section}'. Please check the section name or try again later."
else
echo "BBC News - ${section} section (${count} headlines)"
echo "$headlines"
fi

改良点

  • BBC 英国版とワールド版の両方のセクションを参照できるようにしました。
  • us_and_canada, latain_americaなどはusa(n-usa)、latam(la)など、省略形を引数にできます。

使用例

  • ヨーロッパのニュースを4件表示
./bbc_headline.sh eu 4
BBC News - europe section (4 headlines)
Six killed in strike on Russia's Kursk after deadly missile attack on Kyiv
Child, 7, dies in stabbing at Croatian primary school
Italy's deputy PM Salvini cleared in kidnap trial of migrants blocked at sea
Eight migrants drown after boat tries to evade Greek ship
  • サイエンス分野のニュースを表示
./bbc_headline.sh science
BBC News - science_and_environment section (3 headlines)
Ancient landmarks closed off to walkers, campaigners say
Trouble in Arctic town as polar bears and people face warming world
Nasa astronauts Butch and Suni's homecoming delayed again

後はupdate-motdなどに仕込むことで、ターミナルでログインすると同時にニュースの見出しを見ることができます。

Apache設定ファイル反映を効率化するスクリプトをコマンド化。

先日ご紹介したApache環境のWebサービス再起動を効率的に行うスクリプトをコマンドとして登録します。

コマンドとして登録

  • 実行権限付与
sudo chmod +x apache_check_restart.sh
  • シンボリックリンク付与
sudo ln -s /path/to/script/apache_check_restart.sh /usr/local/bin/apache_check_restart

スクリプトが配置されたディレクトリをフルパスで書きます。

  • シンボリックリンク付与確認
 which apache_check
/usr/local/bin/apache_check_restart

実行例

sudo apache_check_restart
==== 有効なサイト設定ファイル ====
設定ファイル: atelier.conf
ServerName atelier.reisalin.com
servername atelier.reisalin.com
設定ファイル: bookstack.conf
ServerName barrel.reisalin.com
servername barrel.reisalin.com
構文チェック中...
Syntax OK
構文チェック完了: 問題ありません。
Apacheを再起動しますか? (y/n): 

Apacheが正常に再起動されました。

となり、yならapacheサービスを再起動後にステータスを表示。nならそのままスクリプトを抜けます。

Apacheのサービス再起動と確認スクリプト。

Ubuntu 24.04/Apache環境で

  • 再起動前に稼働しているサイトを確認
  • 構文チェック
  • 再起動
  • 再起動後のサービス状況

を一括で行うスクリプトです。

スクリプト

  • apache_check_restart.sh
#!/bin/bash


# サイト設定ディレクトリ
SITES_DIR="/etc/apache2/sites-enabled"

# スクリプトを root ユーザーで実行しているかチェック
if [ "$EUID" -ne 0 ]; then
    echo "このスクリプトは root 権限で実行する必要があります。"
    exit 1
fi

# 1. /etc/apache2/sites-enabled 配下のファイルとURL表示
echo "==== 有効なサイト設定ファイル ===="
if [ -z "$(ls -A $SITES_DIR)" ]; then
    echo "サイト設定が存在しません。"
else
    for site in "$SITES_DIR"/*; do
        echo "設定ファイル: $(basename "$site")"
        # URL部分を含むServerNameやServerAliasをgrepして表示 (重複行を削除)
        grep -Ei "ServerName|ServerAlias" "$site" | sed 's/^[ \t]*//' | sort | uniq
    done
fi

echo "=================================="

# 2. Apache構文チェック
echo "構文チェック中..."
apachectl configtest
if [ $? -ne 0 ]; then
    echo "構文エラーが検出されました。Apacheを再起動できません。"
    exit 1
fi
echo "構文チェック完了: 問題ありません。"

# 3. Apache再起動の確認
read -p "Apacheを再起動しますか? (y/n): " CONFIRM
if [[ "$CONFIRM" =~ ^[Yy]$ ]]; then
    echo "Apacheを再起動します..."
    systemctl restart apache2
    if [ $? -ne 0 ]; then
        echo "Apacheの再起動に失敗しました。"
        exit 1
    fi
    echo "Apacheが正常に再起動されました。"

    # 4. Apacheステータス確認
    echo "==== Apacheステータス ===="
    systemctl status apache2 --no-pager
else
    echo "Apacheの再起動はキャンセルされました。"
fi

root権限で作成し、

sudo chmod +x apache_check_restart.sh

で実行権限を付与します。

動作例

sudo bash apache_check_restart.sh
==== 有効なサイト設定ファイル ====
設定ファイル: atelier.conf
ServerName atelier.reisalin.com
servername atelier.reisalin.com
設定ファイル: bookstack.conf
ServerName barrel.reisalin.com
servername barrel.reisalin.com
構文チェック中...
Syntax OK
構文チェック完了: 問題ありません。
Apacheを再起動しますか? (y/n): 

Apacheが正常に再起動されました。
==== Apacheステータス ====
● apache2.service - The Apache HTTP Server
     Loaded: loaded (/usr/lib/systemd/system/apache2.service; enabled; preset: enabled)
     Active: active (running) since Wed 2024-12-18 08:23:29 JST; 12ms ago
       Docs: https://httpd.apache.org/docs/2.4/
    Process: 335542 ExecStart=/usr/sbin/apachectl start (code=exited, status=0/SUCCESS)
      Tasks: 11 (limit: 4690)
     Memory: 535.1M (peak: 2.2G swap: 0B swap peak: 67.9M)
        CPU: 510ms
     CGroup: /system.slice/apache2.service
             ├─335551 "Passenger core"
             ├─335577 "PassengerWatchdog (cleaning up...)"
             └─335580 /usr/sbin/apache2 -k start

と表示されます。上記、一連の流れを一括で行うので便利です。

CSSの要素を表示するシェルスクリプト。

こういうさらっとしたツールを作る際にGTPは役立ちます。

興味でCSSをいじることがあり、どのCSSにどの要素が含まれているかを解析するためのコードを生成してもらいました。

スクリプト内容

  • css-inspector.sh
#!/bin/bash

# CSSファイルを引数として受け取る
if [ "$#" -ne 1 ]; then
  echo "Usage: $0 <css_file>"
  exit 1
fi

CSS_FILE="$1"

# ファイルが存在するか確認
if [ ! -f "$CSS_FILE" ]; then
  echo "Error: File '$CSS_FILE' does not exist."
  exit 1
fi

# CSS要素を抽出して解説する
awk '
BEGIN {
  print "CSS要素を抽出し、それぞれを解説します:\n"
}
{
  if ($0 ~ /\{/ || $0 ~ /\}/) {
    current_selector = $0
    gsub(/\{|\}/, "", current_selector)
    gsub(/^\s+|\s+$/, "", current_selector)
  }

  if ($0 ~ /font-size/) {
    print "font-sizeが見つかりました: テキストのサイズを指定します。セレクタ -> " current_selector ". 値 -> " $0
  }

  if ($0 ~ /background-color/) {
    print "background-colorが見つかりました: 要素の背景色を定義します。セレクタ -> " current_selector ". 値 -> " $0
  }

  if ($0 ~ /color:/) {
    print "colorが見つかりました: テキストの色を設定します。セレクタ -> " current_selector ". 値 -> " $0
  }

  if ($0 ~ /line-height/) {
    print "line-heightが見つかりました: テキスト行間のスペースを制御します。セレクタ -> " current_selector ". 値 -> " $0
  }

  if ($0 ~ /margin/) {
    print "marginが見つかりました: 要素の周囲の余白を定義します。セレクタ -> " current_selector ". 値 -> " $0
  }

  if ($0 ~ /padding/) {
    print "paddingが見つかりました: コンテンツとボーダー間の余白を定義します。セレクタ -> " current_selector ". 値 -> " $0
  }

  if ($0 ~ /border/) {
    print "borderが見つかりました: 要素のボーダーのスタイル、幅、色を指定します。セレクタ -> " current_selector ". 値 -> " $0
  }

  if ($0 ~ /width/) {
    print "widthが見つかりました: 要素の幅を設定します。セレクタ -> " current_selector ". 値 -> " $0
  }

  if ($0 ~ /height/) {
    print "heightが見つかりました: 要素の高さを設定します。セレクタ -> " current_selector ". 値 -> " $0
  }
}
END {
  print "\nCSS要素の抽出と解説が完了しました。"
}' "$CSS_FILE"

echo "\n完了しました!"

後は

スクリプト実行結果

chmod +x css-inspector.sh

として実行権を付与し、

./css-inspector.sh css_file

で解析します。

CSS要素を抽出し、それぞれを解説します:

font-sizeが見つかりました: テキストのサイズを指定します。セレクタ -> :root. 値 ->   --font-size: 1.1em; /* 1.1emで10%大きく */
font-sizeが見つかりました: テキストのサイズを指定します。セレクタ -> .issue, .description, .journal, .wiki. 値 ->   font-size: var(--font-size); /* 定義したサイズを適用 */
font-sizeが見つかりました: テキストのサイズを指定します。セレクタ -> code, pre. 値 ->   font-size: var(--font-size); /* ターミナル風のフォントでもサイズを変更 */

CSS要素の抽出と解説が完了しました。
\n完了しました!

さっくりとしたものですが、それでも、ターミナル上での視認性が良くなりました。

BBC Newsの見出しを取得するBashスクリプト・改良

概要

以前に書いたBBC Newsの特定のセクションから最新の見出しを取得するBashスクリプトを改良しました。Ubuntu 24.04で動作を確認しています。

必要なライブラリのインストール

このスクリプトを実行するには、xmllintが必要です。

sudo aptitude update
sudo aptitude install libxml2-utils

コード

bbc_headlin.sh

#!/bin/bash

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

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

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

# メインセクションのURLの構築
if [[ ! " ${main_sections[@]} " =~ " ${section} " ]]; then
echo "Error: Invalid section '${section}'. Valid sections are: ${main_sections[*]}"
exit 1
fi

url="https://feeds.bbci.co.uk/news/${section}/rss.xml"

# BBC NewsのRSSフィードから見出しを取得
headlines=$(curl -s "$url" | xmllint --format - | grep -oP '(?<=<title>).*?(?=</title>)' | sed -n '3,'"$((count+2))"'p' | sed 's/<!\[CDATA\[//g' | sed 's/\]\]>//g')

# 見出しの表示
if [ -z "$headlines" ]; then
echo "No headlines found for section '${section}'. Please check the section name or try again later."
else
echo "BBC News - ${section} section (${count} headlines)"
echo "$headlines"
fi

作成後、

chmod +x bbc_headline.sh

としてスクリプトに実行権を与えます。

動作例

このスクリプトの動作例です:

デフォルトのセクション(world)から3つの見出しを取得する場合:

./bbc_headline.sh
  • 出力例:
BBC News - world section (3 headlines)
I hope Assad pays the price, says mother whose son's death inflamed 2011 Syrian revolution
Israel confirms attack on Syrian naval fleet
Another headline example

technologyセクションから5つの見出しを取得する場合:

./bbc_headline.sh technology 5
  • 出力例:
BBC News - technology section (5 headlines)
Tech company announces new product
Breakthrough in AI technology
Another tech headline
More tech news
Latest in technology

見出し数のみを指定する場合(デフォルトのセクションworldを使用):

./bbc_headline.sh 5
  • 出力例:
BBC News - world section (5 headlines)
I hope Assad pays the price, says mother whose son's death inflamed 2011 Syrian revolution
Israel confirms attack on Syrian naval fleet
Another headline example
More world news
Latest in world news

利用可能なセクション

利用可能なセクション
スクリプトで指定できるセクションは、以下の通りです:

  • world: 世界のニュース
  • uk: イギリス国内のニュース
  • business: ビジネス関連のニュース
  • politics: 政治関連のニュース
  • health: 健康関連のニュース
  • education: 教育関連のニュース
  • science_and_environment: 科学・環境関連のニュース
  • technology: テクノロジー関連のニュース
  • entertainment_and_arts: エンターテインメント・アート関連のニュース

メインセクション及び見出し数を引数として利用できるのが改善点です。

Redmineのリマインダースクリプトをもう少し改良。

概要

Redmine標準で備わっているリマインダー。

締め切りが近いチケットを担当者に送付できる機能をcronで登録しています。これを更に改良です。

スクリプト

#!/bin/bash

# 引数でルートディレクトリを指定(デフォルトは/home/www-data/redmine)
REDMINE_ROOT=${1:-"/home/www-data/redmine"}

# 引数で日数を指定(デフォルトは3日)
DAYS=${2:-3}

# Redmineのルートディレクトリに移動
cd $REDMINE_ROOT

# リマインダーを送信
bundle exec rake redmine:send_reminders days=$DAYS RAILS_ENV=production

前は締め切り日数を

./redmine_reminder.sh 5

のように、引数で指定していました。新しいスクリプトでは

./redmine_reminder.sh /home/wwww-data/redmine2 5

と、同一サーバ上にある別Redmineでもルートディレクトリを指定できるようになっています。

後はこれを

20 8 * * * /home/hoge/scripts/redmine_reminder.sh /home/www-data/redmine2 31

など、crontabでの自動化を行いやすくしました。

MySQLのデータベースを暗号化してバックアップするスクリプト。

概要

以前も作成していた、MySQLのデータベースのバックアップを自動的に取得するスクリプトを少々リファインさせました。

変数指定により、複数のDBを任意にバックアップできます。

スクリプトの動き

  • サーバ内にあるDBのバックアップを取得し、暗号化して指定ディレクトリに保存します。
  • 複合化のパスワードはスクリプトが自動生成し、暗号化と同時に別ディレクトリに保存します。
  • cronの自動実行を前提としているため、古い暗号化ファイルと複合化のパスワードは一定期間後に削除を行います。

動作を確認したサーバ

  • Ubuntu 24.04
  • MySQL 8.0.39

前準備

アカウントファイル

任意のディレクトリに、db_account.txtといった、DBにユーザー名とパスワードを記したファイルを作成しておきます。

[client]
user = db_user
password = "password"
  • パーミッションは400にします。(chmod 400 db_account.txt)
  • 取り扱いは慎重に行ってください。

バックアップDBの格納先

  1. 冗長性があり
  2. 機密性が保たれる

場所を指定してください。筆者はクラウドストレージ(wasabi)をマウントしています。

パスワードの格納先

/home/hoge/dbrestore_password のように、複合化のパスワードを格納するディレクトリを作っておきます。
こちらも運用に合わせ、適切に保管ができる場所を指定します。

それぞれ、スクリプト実行アカウントがアクセス/実行できるものにします。

スクリプト

スクリプト内容

  • スクリプトファイル名(例)
    • mysql_db_backup.sh

変数などは間違いの無いように指定ください。

#!/bin/bash

## 変数ここから ##
# $HOMEの変数を指定します。
HOME_DIR="/home/hoge"
# SQLをバックアップするディレクトリ(保管先)を指定します。運用に合わせて指定ください。
backup_dir="/path/to/backup/directory"
# 保持するバックアップの世代を日数で指定します。
keep_days=7
# ファイルに付与する日付/作業ディレクトリ名/バックアップファイル名を指定します。
current_date=$(date +%Y%m%d)
backup_name="backup_mysql_${current_date}"
zip_file="backup_mysql.${current_date}.zip"
# アカウントファイルを指定します。運用に合わせて指定ください。
credentials_file="${HOME_DIR}/script/config/db_account/db_account.txt"
# パスワードを記録するファイル名を指定します。運用に併せてして指定ください。
password_dir="${HOME_DIR}/dbrestore_password"
password_file="${password_dir}/db-restore.${current_date}.txt"
# redmineのデータベース名を指定します。
database_name=database
# バックアップ時に指定するオプションを指定します。
options="--defaults-extra-file=$credentials_file --no-tablespaces --single-transaction"
# バックアップファイルのパターンを指定します。
backup_file_pattern="backup_mysql.*.zip"
# パスワードファイルのパターンを指定します。
password_file_pattern="*restore*.txt"
## 変数ここまで ##

## 処理ここから ##

# 1.アカウントファイルのパーミッションが400かどうかチェックします。
# 400以外は処理そのものを終了します。
permissions=$(stat -c "%a" "$credentials_file")
if [ "$permissions" != "400" ]; then
echo "アカウントファイルのパーミッションは400である必要があります。"
exit 1
fi

# 2.一時的なバックアップディレクトリを作成します。
mkdir "${backup_dir}/${backup_name}"

# 3. mysqldumpを実行してデータベースのバックアップを取ります。
mysqldump $options -h localhost $database_name > "${backup_dir}/${backup_name}/${backup_name}.sql"

# 4. パスワードによる暗号化を実施します。
password=$(openssl rand -base64 12)
cd "${backup_dir}/${backup_name}"
zip -r "${backup_dir}/${zip_file}" -P "$password" .
cd -

# 5. 一時的なバックアップディレクトリを削除します。
rm -rf "${backup_dir}/${backup_name}"

# 6. 解凍パスワードを指定ディレクトリに保存します。
echo $password > $password_file

# 7.パスワードの読み取り権限を600に変更します。
chmod 600 $password_file

# 8. 保持期間より古いバックアップファイルを削除します。
find "$backup_dir" -name "$backup_file_pattern" ! -type f -newermt "${keep_days} days ago" -delete
find "$password_dir" -name "$password_file_pattern" ! -type f -newermt "${keep_days} days ago" -delete

## 処理ここまで ##

作成後、

chmod +x mysql_db_backup.sh

で実行権を付与します。

スクリプトの動かし方

スクリプトの動き

./mysql_db_backup.sh

として実行すると、

  1. 変数で指定したアカウントファイルを読み込み、mysqldumpでバックアップを取ります。
  2. バックアップ作成後、パスワード付きzipファイルに圧縮します。
  3. 圧縮されたバックアップと複合化のためのテキストファイルを変数で指定したディレクトリに格納します。
  4. 変数で指定した期日が過ぎたバックアップファイルと複合化のためのテキストファイルは自動的に削除されます。

バックアップDBの解凍

unzip backup_mysql.yyyymmdd.zip

とすると、パスワードを尋ねられます。

db-restore.yyyymmdd.txtに表示された文字列を入力します。

または、

unzip -P $(cat /path/to/password_file.txt) /path/to/zip_file.zip -d /path/to/output_directory

でファイルを直接引数にして解凍することもできます。

cronの指定

動作を確認したら、

crontab -e -u hoge

でcron編集画面を出し、

0 2 * * * /home/hoge/script/directory/mysql_db_backup.sh

などとして指定すれば、日次のDBバックアップを取得可能です。

サーバにアクセスするIPアドレスの詳細を確認するシェルスクリプト。

Copilotを利用して、以下のスクリプトを抽出です。

  1. netstat -tan |grep ポート番号 を実行
  2. ポート番号は変数で指定可能
  3. IPアドレス一覧と件数を表示
  4. 詳細を表示しますか? → yの場合、IPアドレスが割り当てられている国やホストをIPアドレスごとに表示する
  5. 自分がアクセスしていることを考慮して、表示しないIPアドレスは変数で定義できるものとする
#!/bin/bash

# 定義された除外するIPアドレス(スペースで区切って指定可能)
EXCLUDE_IP="IPアドレスを入力"

# 使用するポート番号(スペースで区切って指定可能)
PORT="80 443"

# netstatを使用して指定されたポートに関連するIPアドレスを抽出
IP_LIST=$(netstat -tan | grep ":$PORT" | awk '{print $5}' | cut -d':' -f1 | grep -vE "($EXCLUDE_IP)" | sort | uniq)

# IPアドレスの件数を表示
echo "IPアドレス一覧:"
echo "$IP_LIST"
echo "件数: $(echo "$IP_LIST" | wc -l)"

# ユーザーに詳細表示を尋ねる
read -p "詳細を表示しますか? (y/n): " DETAIL

if [ "$DETAIL" = "y" ]; then
for IP in $IP_LIST; do
# whoisコマンドを使用してIPアドレスの詳細を取得
echo "IPアドレス: $IP の詳細:"
whois $IP | grep -E 'Country|OrgName' || echo "情報が見つかりませんでした。"
echo "-----"
done
else
echo "詳細表示はスキップされました。"
fi

前提としてwhoisコマンドがインストールされていることが条件。

これによって、

  • どこからアクセスしてくるのか
  • ホストの詳細はあるのか

の確認が可能です。

Page 1 of 6

Powered by WordPress & Theme by Anders Norén