タグ: Linux Page 5 of 29

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コマンドのタイムアウトが設定されたため、ネットワークの問題などで応答がない場合に処理が止まるのを防ぐことができます。

Redmine5.1に文書管理プラグイン(dmsf)をインストールする上での注意点。

こちらの記事の補足となります。

前提

2025/01/23時点のdmsfプラグインの最新バージョンはRedmine 6.0に合わせたものです。

そのため、git cloneする際に

https://github.com/danmunn/redmine_dmsf/releases

を確認して、Redmineのバージョンと合っているかを確認。

その上で

sudo -u www-data git clone -b v3.2.4 https://github.com/danmunn/redmine_dmsf

バージョンを指定してからgit cloneします。

これを怠ると

自分の例ですが、「Redmineそのものが深刻な機能不全を起こしました」。

具体的に言うと

  • チケットを発行、閲覧、更新時にエラーが起きる
  • Something wrongの画面が出る

などです。

重ねての注意点

  1. 強力な機能をもたらすプラグインほどDBや機能に深刻な影響をもたらします。DBのバックアップは必須です。
  2. 本当に動くバージョンかを更に確認。

と、躓いた上での経験談でした。

Redmineのかんばんプラグインの差し替えメモ。

概要

Redmineのプラグインをかんばんからダッシュボードプラグインに差し替えたときのメモです。

環境

  • Ubuntu 24.04
  • Redmine 5.1
  • MySQL 8
  • Ruby 3.2
  • Apache 2.4

さっくりとした手順

  1. DBのバックアップ
  2. 既存のかんばんプラグイン削除
  3. ダッシュボードプラグインインストール
  4. 動作確認

DBバックアップ

  • 作業ディレクトリ移動
cd /hoge && pwd

任意の作業ディレクトリに移動

  • DBバックアップ
mysqldump -h localhost -u redmine -p --no-tablespaces --single-transaction redmine > redmine_backup.$(date +%Y%m%d).sql
  • バックアップ確認
view redmine_backup.$(date +%Y%m%d).sql

Redmine kanbanのアンインストール (退避)

  • ディレクトリ移動
cd /path/to/redmine/root/directory/plugins && pwd
  • kanbanプラグインの退避
sudo mv kanban /path/to/backup/directory/kanban_org_$(date +%Y%m%d)
  • 退避確認
ls -ld /path/to/backup/directory/kanban_org_$(date +%Y%m%d)
  • Webサービス再起動
sudo systemctl restart apache2.service && echo $?

0を確認

Dashboardプラグインのインストール

  • git clone
sudo -u www-data git clone https://github.com/jgraichen/redmine_dashboard
  • clone 確認
ls -ld redmine_dashboard
  • Redmineルートディレクトリに移動
cd /path/to/redmine/root/directory && pwd
  • bundle install
sudo -u www-data bundle install --without development test
  • DBマイグレーション
sudo -u www-data bundle exec rake redmine:plugins:migrate RAILS_ENV=production
  • Webサービス再起動
sudo systemctl restart apache2.service && echo $?

0を確認

確認

  1. Redmineに管理者権限でログイン
  2. 管理>プラグインにRedmine Dashboard pluginがあることを確認
  3. 任意のプロジェクト>設定で「ダッシュボード」を有効化して保存。
  4. プロジェクトのタブにダッシュボードが表示されること、自分が担当するチケットをドラッグアンドドロップで表示されることを確認

Railsのハマり案件。状況収束。

昨日のこの案件は無事に解決。

対処

原因が自分のRails/Rubyによるものが明らかだったので、それぞれの入れ直しです。

Rubyアンインストール

sudo apt remove --purge ruby ruby-dev rubygems
apt autoremove

として、関連のパッケージを全て削除。設定は特にしていなかったのが幸いしました。

Ruby 再インストール

sudo aptitude install ruby libruby ruby-dev libmysqlclient-dev
sudo aptitude install libapache2-mod-passenger

gemで関連パッケージインストール

sudo gem install bundler racc mysql2

apache再起動

sudo systemctl restart apache2.service && echo $?

→ 0が返ってきたので反映もOK。

後はbundle installもDBマイグレーションも無事に通るようになりました。

Railsのハマり案件。状況発生。

前に見たことがないエラーにとっ捕まったため、状況をメモしておきます。

環境

  • Ubuntu 24.04
  • Ruby 3.2

何が起きているか

Redmineの検証のため、新たに5.1を立てています。

  1. SVNでチェックアウト
  2. DBなどを作成
  3. database.ymlにDB情報を追記
 sudo -u www-data bundle exec rake generate_secret_token

実行後、

rake aborted!
NameError: uninitialized constant ActiveSupport::LoggerThreadSafeLevel::Logger (NameError)

    Logger::Severity.constants.each do |severity|
          ^^^^^^^^^^
/home/www-data/hideout/vendor/bundle/ruby/3.2.0/gems/activesupport-6.1.7.10/lib/active_support/logger_thread_safe_level.rb:16:in `<module:LoggerThreadSafeLevel>'
/home/www-data/hideout/vendor/bundle/ruby/3.2.0/gems/activesupport-6.1.7.10/lib/active_support/logger_thread_safe_level.rb:9:in `<module:ActiveSupport>'
/home/www-data/hideout/vendor/bundle/ruby/3.2.0/gems/activesupport-6.1.7.10/lib/active_support/logger_thread_safe_level.rb:8:in `<top (required)>'
<internal:/usr/lib/ruby/vendor_ruby/rubygems/core_ext/kernel_require.rb>:38:in `require'
<internal:/usr/lib/ruby/vendor_ruby/rubygems/core_ext/kernel_require.rb>:38:in `require'
/home/www-data/hideout/vendor/bundle/ruby/3.2.0/gems/activesupport-6.1.7.10/lib/active_support/logger_silence.rb:5:in `<top (required)>'
<internal:/usr/lib/ruby/vendor_ruby/rubygems/core_ext/kernel_require.rb>:38:in `require'
<internal:/usr/lib/ruby/vendor_ruby/rubygems/core_ext/kernel_require.rb>:38:in `require'
/home/www-data/hideout/vendor/bundle/ruby/3.2.0/gems/activesupport-6.1.7.10/lib/active_support/logger.rb:3:in `<top (required)>'
<internal:/usr/lib/ruby/vendor_ruby/rubygems/core_ext/kernel_require.rb>:38:in `require'
<internal:/usr/lib/ruby/vendor_ruby/rubygems/core_ext/kernel_require.rb>:38:in `require'
/home/www-data/hideout/vendor/bundle/ruby/3.2.0/gems/activesupport-6.1.7.10/lib/active_support.rb:29:in `<top (required)>'
<internal:/usr/lib/ruby/vendor_ruby/rubygems/core_ext/kernel_require.rb>:38:in `require'
<internal:/usr/lib/ruby/vendor_ruby/rubygems/core_ext/kernel_require.rb>:38:in `require'
/home/www-data/hideout/vendor/bundle/ruby/3.2.0/gems/railties-6.1.7.10/lib/rails.rb:7:in `<top (required)>'
<internal:/usr/lib/ruby/vendor_ruby/rubygems/core_ext/kernel_require.rb>:38:in `require'
<internal:/usr/lib/ruby/vendor_ruby/rubygems/core_ext/kernel_require.rb>:38:in `require'
/home/www-data/hideout/config/application.rb:5:in `<top (required)>'
<internal:/usr/lib/ruby/vendor_ruby/rubygems/core_ext/kernel_require.rb>:38:in `require'
<internal:/usr/lib/ruby/vendor_ruby/rubygems/core_ext/kernel_require.rb>:38:in `require'
/home/www-data/hideout/Rakefile:5:in `<top (required)>'
/home/www-data/hideout/vendor/bundle/ruby/3.2.0/gems/rake-13.2.1/exe/rake:27:in `<top (required)>'
(See full trace by running task with --trace)

が発生。そのため、DBマイグレーションも通らないという状況。

この問題はやっかいそうなので、まずは事象が発生したという事実だけメモをします。

Redmine 5.1にパスワードマネージャーをインストール&初期設定

概要

性質上、パスワードをやりとりすることが多いRedmine。その管理を一括で行うためのプラグイン、vaultをインストールしてみました。

特記事項

  • ※パスワードを管理するという性質上、インターネットからアクセスできるサイトでこのプラグインの運用はオススメしません。
  • コンフィグファイルをいじるため、可能な限り検証環境でテストを行ってから導入を試みてください。

環境

  • Redmine 5.1
  • Ubuntu 22.04
  • Apache 2.4
  • MySQL
  • Ruby 3.0.2

※筆者環境のRedmineとApacheの実行ユーザーは www-data です。

さっくりとしているけどさっくりとはいかない手順

Redmineサーバでのターミナル操作です。(要管理者権限)

  1. gitでプラグインをcloneします。
  2. DBのマイグレーションを行い、プラグインをインストールします。
  3. Webサービスを再起動します。
  4. 初期設定をWebとターミナルで行います。

プラグインをgit cloneして配置

  • Redmineのプラグイン配置ディレクトリに移動
cd /path/to/redmine/plugins && pwd

自分の環境に合わせます。 (筆者環境 /home/www-data/redmine/plugins )

  • git clone
sudo -u www-data git clone https://github.com/noshutdown-ru/vault
  • clone確認
ls -ld vault

ディレクトリがあることを確認します。

プラグインのインストール

  • Redmineのルートディレクトリに移動
cd /path/to/redmine && pwd

自分の環境に合わせます。 (筆者環境 /home/www-data/redmine )

  • bundle
sudo -u www-data bundle install
  • DB マイグレーション
sudo -u www-data bundle exec rake redmine:plugins:migrate RAILS_ENV=production
  • マイグレーションの成功確認
echo $?

0を確認します。0以外は何らかのエラーが起きています。

Webサービスの再起動

  • Webサービス(apache)再起動
sudo systemctl restart apache2.service && echo $?

0を確認します。0以外は何らかのエラーが起きています。

  • Webサービス起動確認
systemctl status apache2.service

active (running)を確認します。

プラグインのインストール確認と初期設定

  • ブラウザでRedmineにログイン

管理者権限でログインします。ログイン後、ヘッダーにKeysというメニューが表示されています。クリックしても

500
The encryption key is not set in the settings

というエラーが出ていますので、対応を行います。

  • 管理画面に移動

管理>Vaultに移動します。

  • 暗号化キーの設定

暗号化キーを、ランダムな文字列:英数記号16文字で入力します。

head /dev/urandom | tr -dc 'a-zA-Z0-9!@#$%^&*()_+{}|:<>?' | head -c 16; echo

等とすると、16文字の文字列を完全ランダムに生成することができます。

この文字列を「暗号化キー」の後のテキストボックスに入れます。

Use Redmine encryptionにもチェックを入れ、適用をクリックします。

この後、Redmineのサーバにターミナルログインします。

Redmineサーバでのパスワードファイルの暗号化

  • Redmineのコンフィグファイル配置ディレクトリに移動
cd /path/to/redmine/config && pwd

自分の環境に合わせます。 (筆者環境 /home/www-data/redmine/config )

  • configuration.ymlのバックアップ
sudo -u www-data cp -pi configuration.yml /path/to/backup/directory/configuration.yml.$(date +%Y%m%d)

任意のバックアップディレクトリを指定します。

  • configuration.ymlのバックアップ確認
diff -u /path/to/backup/directory/configuration.yml.$(date +%Y%m%d) configuration.yml

差分が無いこと(エラーがないこと)を確認します。

  • configuration.ymlの編集

教義・信仰に則ったエディタを用いて以下のように編集します。

production:
  database_cipher_key: "上記で入力した16文字の文字列"
  • production:の項目がある場合は、そのセクションの下に書きます。
  • その際、と、半角スペース2つを行頭に入れるのを忘れないでください。

編集後、保存をします。

  • configuration.ymlの編集後の差分確認
diff -u /path/to/backup/directory/configuration.yml.$(date +%Y%m%d) configuration.yml
+production:
+  database_cipher_key: "上記で入力した16文字の文字列"

を確認します。(productionが既にある場合は + database_cipher_key: "上記で入力した16文字の文字列" )

  • Redmineのルートディレクトリに移動
cd /path/to/redmine && pwd

自分の環境に合わせます。 (筆者環境 /home/www-data/redmine )

  • configuration.ymlに基づき暗号化
sudo -u www-data bundle exec rake redmine:plugins:vault:convert RAILS_ENV=production
  • 暗号化の成功確認
echo $?

0を確認します。0以外は何らかのエラーが起きています。

Webサービスの再起動

  • Webサービス(apache)再起動
sudo systemctl restart apache2.service && echo $?

0を確認します。0以外は何らかのエラーが起きています。

  • Webサービス起動確認
systemctl status apache2.service

active (running)を確認します。

設定反映確認

  1. Redmineのサイトに管理者権限でログインします。
  2. ヘッダーの Keys をクリックしてエラーがないことを確認します。

使い方に関しては改めて。

Firefly-III 1年間の検証結果と運用レビュー

オープンソースの家計管理システム「Firefly-III」を使い始めてから1年が経過しました。この1年間の運用を通じて、得られた知見や感想をまとめました。最初に導入した環境や特徴的なポイントについて、振り返ってみます。

環境の構築

最初にインストールした環境は、Ubuntu 20.04にPHP 8.1を使用していましたが、その後、Ubuntu 24.04とPHP 8.3にアップグレードしました。

(インストールのメモはこちら)

構築自体はWordpressの構築実績があれば理解可能で、公式ドキュメントに従うことでスムーズに進みました。特に専門的な知識がなくても、簡単に運用を開始できる点は大きな魅力でした。

入力の簡便さ

家計簿の管理で最も重要なのは、入力の手間をいかに減らすかです。Firefly-IIIでは、サブスクリプションや保険料など、毎月定期的に発生する費用を簡単にコピーして入力できる機能があり、手間を大幅に削減できました。これにより、月ごとの出金管理が非常に楽になりました。

直感的なインターフェース

「Firefly-III」のインターフェースは非常に直感的で、出金、入金、送金というシンプルな3つの取引項目で構成されています。このシンプルさにより、簿記などの知識に乏しくても迷うことなく運用できるようになりました。

視覚的な管理: グラフの活用

「Firefly-III」では、家計の動きをグラフで視覚化できるため、特に大きな支出がある場合に、どのくらいの金額が減るのかが一目で分かります。また、クレジットカードのような未来の引き落としもグラフに表示されるため、前もって支出を把握することができます。

予算管理とモチベーションの向上

予算を設定することで、趣味や娯楽に使うお金の限度を決めることができ、(ある程度の)無駄遣いを防げました。デジタルガジェットの購入やフィギュアの予約などに備えて出費を抑えられるようにもなりました。

また、「Firefly-III」では予算管理以外にもカテゴリー分けができ、食費や日用品などを細かく把握することができました。これにより、家計全体のバランスをよりよく理解できるようになりました。

入出金は極めて有用なライフログ

家計簿をつけることで、いつ、どこで、何に、どれくらい使ったかという行動の記録が残ります。この記録は、単なる金銭的な管理にとどまらず、ライフログとしても非常に有用です。例えば、病院での支出を記録することで、いつ、どの病気にかかったかがわかり、過去の体調管理にも役立ちました。

また、突発的な出来事の際に、どのような出金が発生したかも目の当たりにできました。

旅行時の支出記録

旅行中も「Firefly-III」は大いに役立ちました。どんな店で何を食べたのか、お土産を買ったのかなど、旅行の詳細を記録しておくことで、後から振り返って思い出に浸ることができました。

すべての支出を記録するのは大変

一方で、全ての支出を記録するのはやはり大変です。LINEなどのトークアプリで自分自身にメモを送ることで忘れずに記録していますが、入力ミスや記録漏れが発生することもあり、後で差分をチェックすることが課題として残っています。

とはいえ、自分自身の予算管理のために多少の誤差は許容できる範囲であり、精度向上のための改善は引き続き行っています。

運用に関する課題

「Firefly-III」をサーバーで管理するため、サーバー運用に関する一定の知識が必要です。また、お金の流れという非常にセンシティブな情報を扱うため、慎重な運用が求められます。

データのセキュリティやバックアップについても配慮が必要です。

今後の目標

今後は、「Firefly-III」のタグ機能を活用して、さらに細かく支出のカテゴリーを分けて管理していく予定です。

また、自動的に支出が登録される仕組み(例えばAPIやスマートフォンアプリを活用)を導入することで、手間をさらに減らすことを目指しています。最終的には、資産の流れをより明確に把握し、効果的な予算の策定を行いたいと考えています。

1年間の運用を通じて、Firefly-IIIは家計管理を効率的に行うための強力なツールであることが実感できました。今後も継続して使いながら、より精度の高い予算管理を目指していきたいと思います。

パスワード生成のrubyスクリプト・改。

以前のスクリプトを改良です。

スクリプト内容

  • password_generate.rb
# パスワード生成関数
def generate_password(length, complexity, password_count, exclude_similar)
  # 発行強度に応じた文字セットを選択
  base_chars = {
    1 => [('a'..'z'), (0..9)],
    2 => [('a'..'z'), ('A'..'Z'), (0..9), ['!', '@', '#', '$', '%', '^', '&', '*']],
    3 => [('a'..'z'), ('A'..'Z'), (0..9), ['!', '@', '#', '$', '%', '^', '&', '*'], ['-', '_', '=', '+', '<', '>', '?']]
  }

  chars = base_chars[complexity].map(&:to_a).flatten

  # 見た目が似ている文字を除外
  similar_chars = %w[i l 1 I o O 0 |]
  chars -= similar_chars if exclude_similar

  if chars.empty?
    puts "文字セットが空です。条件を入力してください。"
    return
  end

  # 指定された数のパスワードを生成
  password_count.times do |i|
    password = Array.new(length) { chars.sample }.join
    puts "Password #{i + 1}: #{password}"
  end
end

# 発行強度入力関数
def get_complexity
  puts "発行強度を選択してください:\n"
  puts "1: 小文字と数字のみ(例: a1b2c3)- 8文字\n"
  puts "2: 小文字、大文字、数字、基本記号(例: Abc1@3)- 10文字\n"
  puts "3: 小文字、大文字、数字、基本記号、追加記号(例: Ab1@-+?)- 12文字\n"
  print "発行強度を1から3の範囲で入力してください (デフォルトは2): "

  complexity_input = gets.chomp

  complexity = complexity_input.empty? ? 2 : complexity_input.to_i

  until (1..3).cover?(complexity)
    print "有効な範囲で入力してください(1から3): "
    complexity = gets.chomp.to_i
  end

  complexity
end

# パスワード数入力関数
def get_password_count
  print "表示するパスワードの数を入力してください (デフォルトは4): "
  count_input = gets.chomp

  count = count_input.empty? ? 4 : count_input.to_i

  count
end

# 見た目が似ている文字を除外するかの入力関数
def get_exclude_similar_option
  print "見た目が似ている文字 (例: i, l, 1, 0) を除外しますか?(y/N): "
  exclude_input = gets.chomp

  %w[y Y].include?(exclude_input)
end

puts "パスワードを生成します。"
complexity = get_complexity
password_count = get_password_count
exclude_similar = get_exclude_similar_option

# 発行強度に応じたパスワード長を設定
length_by_complexity = { 1 => 8, 2 => 10, 3 => 12 }
password_length = length_by_complexity[complexity]

# パスワードを生成
generate_password(password_length, complexity, password_count, exclude_similar)

実行例

ruby password_generate.rb

パスワードを生成します。
発行強度を選択してください:
1: 小文字と数字のみ(例: a1b2c3)- 8文字
2: 小文字、大文字、数字、基本記号(例: Abc1@3)- 10文字
3: 小文字、大文字、数字、基本記号、追加記号(例: Ab1@-+?)- 12文字
発行強度を1から3の範囲で入力してください (デフォルトは2): 2
表示するパスワードの数を入力してください (デフォルトは4): 3
見た目が似ている文字 (例: i, l, 1, 0) を除外しますか?(y/N): n
Password 1: &o26_yTt/j
Password 2: LWn8byl8lO
Password 3: .7R2B/QVHI

として、対話的かつ柔軟なパスワードの生成が可能になりました。

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などに仕込むことで、ターミナルでログインすると同時にニュースの見出しを見ることができます。

Page 5 of 29

Powered by WordPress & Theme by Anders Norén