2023/10/05

みずほ銀行 (再訪)

以前作成した みずほ銀行のオンラインバンキングで振り込みをする場合に必要な 第2暗証番号から指定された4桁の番号を見つけ出すためのスクリプト を、 最新のご利用カード (アプリ版) に対応させてみました。 こちらも awk (1) だけで書いたのでどんな環境でも動作する筈です。
第1引数は必須でご利用カード (アプリ版) で生成された第2暗証番号を指定します。
第2引数で番号を指定するか端末から入力すると対応する数字が表示されます。
こんなピンポイントでしか役立たないスクリプトを利用する人がいるかどうか不明ですが折角なので公開だけはしてみます。
(そもそもアプリで振り込めば第2暗証番号の入力自体不要なんですよね...)

  1#!/bin/sh
  2#
  3
  4myname=$(basename $0)
  5
  6error()
  7{
  8
  9    echo "$*" 1>&2
 10
 11    exit 255
 12
 13}
 14
 15if [ -n "${1}" ]
 16then
 17    if [ ${#1} -eq 6 ]
 18    then
 19        awk -v "base=${1}" '
 20            BEGIN{
 21                if("'$2'")
 22                    num = "'$2'"
 23                else{
 24                    printf "Input number: "
 25                    getline num < "/dev/tty"
 26                }
 27                split(num, nums, "");
 28                for(i=1; i<=4; i++)
 29                    printf "%s ", substr(base, nums[i], 1)
 30                print
 31            }
 32        ' < /dev/null
 33    else
 34        error "${myname}: base is 6 digit."
 35    fi
 36else
 37    error "Usage: ${myname} base [nnnn]"
 38fi
    

2021/05/06

/dev を復旧する

とある事情で Linux マシンの /devを殆ど全削除してしまったので復旧してみた。

chroot 環境で作業するスクリプトが chroot 環境を抜けるときに後始末として環境内の /dev等を削除しているのだが、 スクリプトの不具合で chroot 環境から抜けた後(むしろ不具合で chroot できなかった場合) にも /dev の削除処理が 動作してしまったので実環境の /dev が根こそぎ削除されてしまうという...何ともアレな BUG を踏み抜いた次第。

今回はたまたま同じ構成の Linux マシンがもう一台手元にあったので、 そちらの /dev 環境から情報を取得して mknod を実行するためのコマンドライン引数を取得する処理を作成した。

デバイス名やメジャー番号、マイナー番号は /dev 以下の全エントリの詳細情報を find (1) を利用して ls (1) を実行する事で取得し、 その出力を awk (1) を利用して加工し mknod (1) のコマンドライン形式として出力している。
作成するデバイスノードのオーナーとグループは ls (1) の出力から chown (1) コマンドを実行して設定している。 アクセス権限は ls (1)の出力は直接 chmod (1) コマンドで利用できないので、 stat (1) コマンドの出力書式に --format '%04a' を指定する事で 4桁の8進数として取得した値を利用して chmod (1) コマンドで設定している。

stat (1)--format オプションは GNU による独自拡張なので FreeBSD や macOS の純正 stat (1) では動作しないと思う。

/dev には他にもディレクトリ、シンボリックリンクが存在しているので ls (1) の出力からエントリーのタイプを判断し、 ディレクトリの場合は mkdir (1)、シンボリックリンクの場合は ln (1) を適宜実行している。

  1#!/bin/sh
  2
  3find /dev -exec ls -l {} \; |
  4    awk '
  5        # ディレクトリ作成
  6        function mkdir(name) 
  7        {
  8            "dirname " name | getline dirname
  9            if(dirname != "/dev")
 10                printf("mkdir -p %s\n", dirname)
 11            return dirname
 12        }
 13
 14        {
 15            if(NF > 3){
 16                # エントリーの種類取得
 17                type = substr($1, 1, 1)
 18                if(type == "c" || type == "b"){
 19                # デバイスノードの場合
 20                    # 親ディレクトリ作成
 21                    mkdir($NF)
 22                    # 権限取得
 23                    "stat --format '%04a' " $NF | getline mode
 24                    # コマンド出力
 25                    printf "if [ ! -%s %s ]; then  rm -f %s; mknod %s %s %d %d; fi; chown %s:%s %s; chmod %d %s\n",
 26                        type, $NF, $NF, $NF, type, $5, $6, $3, $4, $NF, mode, $NF 
 27                } else if(type == "d"){
 28                # ディレクトリの場合
 29                    # 権限取得
 30                    "stat --format '%04a' " $NF | getline mode
 31                    printf "if [ ! -%s %s ]; then rm -f %s; mkdir -p %s; fi; chown %s:%s %s; chmod %d %s\n",
 32                        type, $NF, $NF, $NF, $3, $4, $NF, mode, $NF 
 33                } else if(type == "l"){
 34                # シンボリックリンクの場合
 35                    # 親ディレクトリ作成
 36                    cwd = mkdir($(NF - 2))
 37                    printf "if [ ! -L %s ]; then rm -f %s; (cd %s; ln -s %s %s); fi\n",
 38                        $(NF-2), $(NF-2), cwd, $NF, $(NF-2)
 39                } else {
 40                    print type " " $0 > "/dev/stderr"
 41                }
 42            }
 43        }
 44    '
    

情報を取得するマシンでこのスクリプトを実行すると /dev を復元するためのコマンドが生成されるので、 /dev 環境がなくなってしまったマシンに転送して実行する事で /dev が復元できる。

必要に応じてその場で適当に作ったスクリプトなので完全無保証。
自分の場合は復旧できて今でもちゃんと動作している。

2020/07/22

awk による IPv4 アドレスのマッチ処理

標準入力から入力されるテキストデータから IPv4 アドレスを awk(1) を利用して抽出する。
その際に CIDR 形式でないアドレスに関しては末尾に "/32" を付与して CIDR 形式にして出力する。

  1awk '{
  2    if(match($0, /([[:digit:]]{1,3}\.){3}[[:digit:]]{1,3}(\/[[:digit:]]{1,2})?/))
  3        print match((ip = substr($0, RSTART, RLENGTH)), /\/[[:digit:]]{1,2}/) ? ip : ip "/32";
  4}'
    

1 行目の match() 関数で入力データから正規表現を利用して IPv4 アドレスを抽出し、 2 行目の substr() 関数を利用してマッチした範囲を切り出して IPv4 アドレスを変数 ip に格納している。 2 行目の match() 関数で変数 ip に格納された IPv4 アドレスにに CIDR 部分があるかを調査し、 CIDR 部がない場合は "/32" を付与して出力している。

IPv4 アドレスは "192.0.2.1" の様に「0 から 9 までの数字 1 桁から 3 桁が "." を挟んで 4 組連続する」形式で、 CIDR は "/24" の様に「"/" に続いて 0 から 9 までの数字 1 桁から 2 桁」なので、 正規表現は

[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}(\/[0-9]{1,2})?
となるが、 煩雑になるので
([0-9]{1,3}\.){1,3}[0-9]{1,3}(\/[0-9]{1,2})?
とまとめ、 更に数字部分を POSIX クラスに置き換えて
([[:digit:]]{1,3}\.){1,3}[[:digit:]]{1,3}(\/[[:digit:]]{1,2})?
とした。

入力データ中の IPv4 アドレスが重複する可能性がある場合は、直接出力せず一度連想配列に格納する事で uniq(1) 相当の処理も可能となる。

  1awk '{
  2    if(match($0, /([[:digit:]]{1,3}\.){3}[[:digit:]]{1,3}(\/[[:digit:]]{1,2})?/))
  3        list[match((ip = substr($0, RSTART, RLENGTH)), /\/[[:digit:]]{1,2}/) ? ip : ip "/32"] = 1;
  4} END {
  5    for(i in liset)
  6        print i;
  7}'
    

2019/10/31

exif 情報を利用した画像の整理スクリプト

iPhone で撮影した画像を macOS 標準の イメージキャプチャ などを利用して Mac に取りこんだ後、 exif 情報を参照して画像ファイルを整理するスクリプトです。
利用するためには exiftool が必要となりますので、Homebrew または MacPorts を利用して導入して下さい。

macOS 10.14.6 (Mojave) での動作を確認していますが、exiftool 以外は POSIX に準拠したコマンドしか使っていないので、 exiftool さえ準備できれば他のバージョンの macOS はもちろん、FreeBSD や Linux 上でも稼働すると思います。

  1#!/bin/sh
  2# 検索する exif タグ
  3tag="DateTimeOriginal ModifyDate CreateDate"
  4
  5# 生成する画像ファイル名に追加する文字列
  6id="_iOS"
  7
  8# 画像ファイル格納先ディレクトリ
  9base=${HOME}/CameraFiles
 10picture="Pictures"
 11movie="Movies"
 12unknown="Unknown"
 13
 14#
 15# exif 情報から画像の作成日を取得
 16#   $1: ファイル
 17#
 18getDate()
 19{
 20
 21    local   _t _d
 22
 23    for _t in ${tag}
 24    do
 25        _d=$(exiftool -${_t} "${1}")
 26        if [ -n "${_d}" ]
 27        then
 28            echo ${_d} | awk '{ print $(NF-1), $(NF)}' | sed -e 's/:/ /g' -e 's/\..*//g'
 29            return
 30        fi
 31    done
 32
 33}
 34
 35#
 36# 格納先のファイル名を生成
 37# ファイル名は ${base}/TYPE/YYYY/MM/YYYYMMDD_HHMMSSXXX_iOS.EXT の形式
 38# XXX は 000 から 999 までを自動で採番する
 39#   $1: 格納先ディレクトリ
 40#   $2: 日付 (YYYYMMDD)
 41#   $3: 時間 (YYYYMMDD)
 42#
 43getName()
 44{
 45
 46    local   _n _nn
 47
 48    _n=1
 49
 50    while [ ${_n} -le 999 ]
 51    do
 52        _nn=$(printf "%03d" ${_n})
 53        if ls "${1}/${2}_${3}${_nn}${id}"* > /dev/null 2>&1
 54        then
 55            _n=$((_n + 1))
 56        else
 57            break
 58        fi
 59    done
 60
 61    echo "${1}/${2}_${3}${_nn}${id}"
 62
 63}
 64
 65#
 66# メイン処理
 67#
 68ls -1 *jpg *png *mov | while read i
 69do
 70    # ファイルの拡張子取得
 71    ext="${i##*.}"
 72
 73    # 拡張子でサブディレクトリを指定
 74    if [ "${ext"} = "mov" ]
 75    then
 76        type="${movie}"
 77    else
 78        type="${picture}"
 79    fi
 80
 81    # exif 情報から作成日を取得
 82    set -- $(getDate "${i}")
 83    year=${1}
 84    month=${2}
 85    day=${3}
 86    time=${4}${5}${6}
 87
 88    if [ -n "${year}" ]
 89    then
 90        # 作成日が取得できた場合
 91        dst="${base}/${type}/${year}/${month}"
 92        name="$(getName "${dst}" "${year}${month}${day}" "${time}").${ext}"
 93    else
 94        # 作成日が取得できない場合
 95        dst="${base}/${type}/${unknown}"
 96        name="${dst}/${i}"
 97    fi
 98
 99    # 格納先ディレクトリ作成
100    mkdir -p "${dst}"
101    # ファイル格納
102    cp "${i}" "${name}"
103done
    

2019/04/18

CentOS 7 のコンソール画面でキーマップを変更する

キーボードのキーが押下されるとキーコードと呼ばれる一意の値がシステムに通知される。
キーマップはこのキーコードに対して文字を定義するためのファイルで、 システム標準のキーマップは /lib/kbd/keymaps/legacy/i386/qwerty に格納されている。
CentOS 7 のコンソール画面のキーマップ情報は /etc/vconsole.conf ファイルに格納されていて、 起動時に自動で読み込まれコンソール画面のキーマップが設定される。

$ cat /etc/vconsole.con
KEYMAP="us"
FONT="latarcyrheb-sun16"
    

例えば US 配列のキーボードで邪魔な Caps Lock を Control に変更したい場合は Caps Lock のキーコードを調べて押下された時に Control が入力される様なキーマップを用意すれば良い。
キーマップは showkey コマンドで調査する事ができる。
showkey コマンドは画面に表示されている通り最後の入力の10秒後に終了する。

$ showkey
kb mode was UNICODE
[if you are trying this under X, it might not work
since the X server is also reading /dev/console ]

press any key (program terminates 10s acter last keypress)...
keycode 58 press                      ここで Capl Lock キーを押下
keycode 58 release                    ここで Capl Lock キーを離す
$
    
結果から Caps Lock キーのキーコードは 58 なのでキーコード 58 に対して Control を入力するキーマップを作成する。 キーマップファイルは他のキーマップファイルを読み込む事ができるので、オリジナルの us.map を読み込んで Caps Lock だけを変更する。 この時、Shift + Caps Lock の場合は Caps Lock としてみる。
キーマップファイルは gzip 形式で圧縮する必要があるので圧縮し、所定のディレクトリに格納する。
# cat << EOF | gzip -c > /lib/kbd/keymaps/legacy/i386/qwerty/us-nocaps.map.gz
include "us.map"

keycode 58 = Control
    shift keycode 58 = Caps_Lock
EOF
    

キーマップファイルの準備ができたら loadkeys コマンドでキーマップを読み込み挙動を確認する。

# loadkeys /lib/kbd/keymaps/legacy/i386/qwerty/us-nocaps.map.gz
Loading /lib/kbd/keymaps/legacy/i386/qwerty/us-nocaps.map.gz
    
Caps Lock キーが Control に、Shift + Caps Lock キーが Caps Lock になる事が確認できたら、 起動時にキーマップが読み込まれる様に /etc/vconsole.conf ファイルを編集する。
# cp /etc/vconsole.conf /etc/vconsole.conf.orig
# sed '/KEYMAP/ s/us/us-nocaps/' /etc/vconsole.conf.orig > /etc/vconsole.conf
    
これで再起動しても Caps Lock は Control となる。

2019/02/15

時間の範囲を指定してログを抽出する

syslog や apache のログファイルなどから時間の範囲を指定してログを抽出したい場合、 ログファイルの時間表記をそのまま比較するのは面倒なので一度 epoch に置き換えて比較すると楽だ。

現在時刻から epoch は date (1) のフォーマット指定 '+%s' を利用する事で取得できるが、 指定した時刻から epoch を取得する汎用的な手法は現状では存在しないので今回は GNU date の '-d' オプションを利用する。

例として combined 形式の apache のログの時間範囲を抽出してみる。
combined 形式の apache のログは以下のフォーマットとなっているので、時刻は空白区切りの4番目のフィールドに格納されている。 そこで、ログの行毎に4番目フィールドの時刻を epoch に変換して比較する事で指定された時間内のログを抽出できる。

192.168.15.134 - - [14/Feb/2019:03:35:54 +0900] "GET / HTTP/1.1" 200 1920 "-" "Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)"
192.168.99.23 - - [14/Feb/2019:07:20:35 +0900] "GET / HTTP/1.1" 200 1920 "https://www.bsdhack.org/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36; 360Spider"
192.168.157.241 - - [14/Feb/2019:09:28:45 +0900] "GET / HTTP/1.1" 200 1920 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36"
192.168.15.143 - - [14/Feb/2019:09:58:44 +0900] "GET /bsdhack.css HTTP/1.1" 200 3246 "-" "Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)"
192.168.93.5 - - [14/Feb/2019:12:03:47 +0900] "GET / HTTP/1.1" 200 1920 "-" "Mozilla/5.0 (Windows NT 6.0) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.41 Safari/535.1"
    

ただし、標準的な apache のログに格納されている時刻情報はそのままでは date (1) の '-d' オプションでは変換できない。

$ date -d "14/Feb/2019:09:28:45"
date: invalid date `14/Feb/2019:09:28:45'
    
そこで、 まずは date (1) で変換できる様な形式に変換してから変換する。 そのためには日付けの区切り文字 '/' と、日付け部と時間部を分割している ':' をスペースに置換すれば良い。
$ date -d "14 Feb 2019 09:28:45"
Thu Feb 14 09:28:45 JST 2019
    
全体の流れとしてはログファイルから1行ずつ読み込み、時刻フィールドを epoch に変換して基準時刻と比較する処理を行う。 今回は全ての処理を awk (1) を利用して実装してみる。

  1#!/bin/sh
  2#   $1: 開始時間 -- date(1) が認識できる形式
  3#   $2: 終了時間 -- date(1) が認識できる形式
  4#   $3: ログファイル
  5
  6# 開始時間
  7start=$(date '+%s' -d "${1}")
  8# 終了時間
  9end=$(date '+%s' -d "${2}")
 10# ログ抽出
 11awk -v "start=${start}" -v "end=${end}" '{
 12    # 時刻フィールドを date(1) が認識できる形式に変換
 13    gsub(/[][/]/, " ", $4)
 14    sub(/:/, " ", $4)
 15    # ログの各行について時刻を epoch に変換する
 16    # $4 にはスペースが含まれているので全体をクォートする
 17    cmd = sprintf("date +%%s -d '"'%s'"'", $4);
 18    # date(1) を実行して epoch を変数 s に取得
 19    cmd | getline s;
 20    # コマンド実行でオープンされたディスクリプタをクローズ
 21    close(cmd);
 22    # 行が範囲内なら出力する
 23    if(start <= s && end >= s)
 24        print $0
 25}' ${3}
    

これで開始時間から終了時間の間のログを抽出できる。
行毎に時間の変換処理を実行するので実行に時間はかかってしまうのが現状の問題点。

2019/01/31

とあるサイトが変更になった時になるべく確実に変更通知を受け取りたい

なるべく確実に変更通知を受け取るためには、普段携行している iPhone への通知が一番良さそうに思う。
iPhone への通知で一番最初に思い浮かぶのは PUSH通知 (APNS) なのだが、 APNS を利用するためには Apple への Developer 登録などが必要で、そう簡単に送る事ができないと思う (Developer 登録などが不要で簡単に PUSH 通知を送る方法があれば是非教えて下さい)。

そこで iPhone で受信しているアドレスにメールを送信し、 更に普段からチェックしている slack で自分宛にダイレクトメッセージを送信する事にした。
iPhone の設定によりメールを受信した時や slack でダイレクトメッセージが投稿された時の通知を有効にする事で、 変更通知がなるべく確実に受け取れる事になると思う。

そのために以下のスクリプトを Linux などが稼働しているサーバ設置して cron などにより自動実行する。

  1#!/bin/sh
  2
  3# site
  4url="https://www.example.com"
  5old=${HOME}/.old.html
  6new=${HOME}/.new.html
  7# for mail
  8addr="mail@exapmle.net"
  9subject="[SITE CHANGEED]"
 10body="SITE CHANGED: ${url}" 
 11# for slack
 12slack="https://hooks.slack.com/services/XXXXXXXXX/YYYYYYYYY/ZZZZZZZZZZZZZZZZZZZZZZZZ"
 13name="name"                 # post name
 14channel="#channel"          # post channel
 15
 16curl -s ${url} > ${new}
 17test -f ${old} &&  
 18cmp -s ${old} ${new} || echo "${body}" | mail -s "${subject}" ${addr} &&
 19curl -sLX POST --data-urlencode "payload={\"channel\": \"${channel}\", \"username\": \"${name}\", \"text\": \"${body}\"}" ${slack}
 20
 21mv $new $old
    
slack でチャンネルではなくダイレクトメッセージを送信する場合は channel の値を適切に変更する。
web を検索すると `channel: @名前` とすれば良いとの記事を多く見かけるが、少なくとも最近の slack ではエラーとなってしまう。
その場合、slack の web 画面の左側に表示されている `ダイレクトメッセージ` をクリックした時に遷移するページの URL の最後の部分 (https://XXX.slack.com/messages/YYYYY/YYYYY の部分) を指定するとダイレクトメッセージが送信できる。

2017/11/29

迷惑メール対策

最近、自宅に届く迷惑メールの量が急増しているのでドメイン単位で受信を拒否するスクリプトを作成した。
自宅メールサーバ環境では mh (1) を利用しているので、迷惑メールは spam フォルダに格納する事を想定している。
メールの自動振り分け処理も mh に付属の slocal (1) コマンドを利用しているので、 迷惑メイルの送信元ドメインを ${HOME}/.maildelivery に格納する様にしている。

  1domains=/etc/postfix/generics-domains                   # 自分のドメインを格納しているファイル
  2spamdir=$HOME/.Mail/spam                                # 迷惑メールを格納しているディレクトリ (1メール1ファイル)
  3delivery=$HOME/.maildelivery                            # maildelivery ファイル
  4tmpdir=/tmp/spam.$$                                     # 一時ファイル
  5reject="/etc/postfix/reject"                            # postfix リジェクトファイル
  6count=0
  7
  8if [ $(ls -1 ${spamdir} | wc -l) -gt 0 ]
  9then
 10    # spam ディレクトリのメールファイルから From を取得
 11    for i in $(sed -n '/^From/ s/.*<.*@\(.*\)>.*/\1/gp' ${spamdir}/* | sort | uniq)
 12    do
 13        # From が自分のドメインに詐称されていない送信ドメインを maildelivery ファイルに "destroy" として追加
 14        grep -q ${i} ${domains} || grep -q "\"@${i}\"" ${delivery} || { printf "from\t\"@%s\"\t\t\tdestroy\tA\t-\n" $i; count=$((count + 1)); }
 15    done >> ${delivery}
 16
 17    # 迷惑メールがある場合
 18    if [ ${count} -gt 0 ]
 19    then
 20        # 迷惑メールの学習
 21        mkdir -p ${tmpdir}
 22        cp -r ${spamdir} ${tmpdir}
 23        sa-learn --spam ${tmpdir}
 24        rm -r ${tmpdir}
 25    fi
 26
 27    # 迷惑メール削除
 28    rmm all +spam
 29
 30    # reject ファイル作成
 31    awk '{
 32        if($1 == "from" && $3 == "destroy" && $2 !~ "@\"$"){
 33            gsub("[\"@]", "", $2)
 34            if ($2 ~ /.+\..+/)
 35                printf "%s DISCARD\n", $2;
 36        }
 37    }' ${delivery} > ${reject}
 38    # HASH 形式に変換
 39    postmap ${reject}
 40    # 再読み込み
 41    service postfix reload
 42fi
    

メールを処理する時に迷惑メールは spam フォルダに仕分ける必要はあるが、このスクリプトを crontab に仕込んでおけば mh (1) の spam フォルダに格納されているメールの送信元ドメインからのメールは拒否出来る様になる。
reject ファイルが肥大してしまうのが難点なのだが迷惑メールは目に見えて減ったので重宝している。

2017/11/06

SSL 証明書の更新チェック

最近は Let's Encrypt を利用する機会が多くなっているので SSL 証明書の更新は基本的に自動で実行しているが、 通常の SSL 証明書の場合は有効期間のチェックが必要なので定期的にチェックするスクリプトを作成した。
このスクリプトは SSL 証明書から有効期限を取得し現在の日付と比較してチェックを行い、

  • 有効期間が 30 日以内の場合は 1 日に 1 度
  • 有効期間が 10 日以内の場合は実行するたび
slack にメッセージを投稿する。
ubuntu サーバでの動作を前提としたスクリプトなので SSL 証明書ファイルは /etc/apache2/sites-enables/0000-default-ssl.conf から取得しているが、 SSL 証明書ファイルを直接指定する事で汎用的に動作させる事が可能となっている。
slack に投稿するためには予め slack にアクセスし Webhook URL を取得する必要がある。

  1#!/bin/sh
  2# SSL 証明書の有効期限をチェックして slack に通知する
  3# 1日数回の実施 (10:00 / 13:00 / 16:00 / 18:00) を想定している
  4
  5host=${1:-`hostname`}
  6cert=$(awk '{ gsub(/#.*/, ""); if($1 == "SSLCertificateFile") print $2; }' /etc/apache2/sites-enabled/000-default-ssl.conf)
  7check=/tmp/sslcheck-send
  8
  9# slack の API フック指定
 10target='https://hooks.slack.com/services/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
 11user="${host} SSLチェック"
 12
 13# リミット
 14soft=$((30 * 24 * 60 * 60))
 15hard=$((10 * 24 * 60 * 60))
 16
 17send_slack()
 18{
 19
 20    icon=${1}
 21    shift
 22
 23    curl -X POST -H 'Content-type: application/json' --data '{"text": "'"${*}"'", "icon_emoji": "'"${icon}"'", "username": "'"${user}"'" }' ${target} > /dev/null 2>&1
 24
 25}
 26
 27# 証明書から有効日を取得
 28limit=$(date -d "$(openssl x509 -noout -text -in ${cert} | sed -n '/Not After/s/.* : \(.*\).*/\1/p')" '+%Y/%m/%d %H:%M:%S')
 29limit_s=$(date -d "${limit}" '+%s')
 30today=$(date -d "00:00:00" '+%Y/%m/%d %H:%M:%S')
 31today_s=$(date -d "${today}" '+%s')
 32
 33current_s=$((${limit_s} - ${today_s}))
 34current=$((current_s / (24 * 60 * 60)))
 35
 36if [ ${current_s} -lt 0 ]
 37then
 38    # 証明書期限切れ
 39    send_slack ":red_circle:" "*ホスト${host}のSSL証明書の期限が${limit}で終了しています。大至急更新作業をして下さい。*"
 40    echo ${update} > ${check}
 41elif [ ${current_s} -le ${hard} ]
 42then
 43    # 証明書期限まで残り 10 日以内
 44    send_slack ":bangbang:" "_ホスト${host}のSSL証明書の期限が${limit}までです (残り${current}日)。至急更新作業をして下さい。_"
 45elif [ ${current_s} -le ${soft} ]
 46then
 47    # 証明書期限まで残り 30 日以内 (1日1回通知)
 48    update=$(date '+%m%d')
 49    if [ -f ${check} -a "$(cat ${check})" -eq ${update} ]
 50    then
 51        :
 52    else
 53        send_slack ":warning:" "ホスト${host}のSSL証明書の期限が${limit}まです (残り${current}日)。更新作業をして下さい。"
 54        echo ${update} > ${check}
 55    fi
 56fi
    

このスクリプトを crontab などで一日数回自動的に実行する様に設定すると、定期的に SSL 証明書の有効期限が確認できる。
slack を利用していない場合、send_slack の部分を変更する事でメール送信などに変更する事ができる。

メール送信する場合のサンプルも以下に示す。
この例では POSIX 準拠のコマンド以外に nkf(1) と base64(1) が必要となっている。

  1send_mail()
  2{
  3
  4    sendmail="/usr/sbin/sendmail -i -t"
  5    from="送信元メイルアドレス"
  6    to="受信先メイルアドレス"
  7    subject=$(echo "サブジェクト" | nkf -WM)
  8    body=$(echo ${*} | sed -e "s/;/\n/g" -e "/^\$/s/\$/\r/" -e "/[^\r]\$/s/\$/\r/" | base64)
  9
 10    cat << EOF | ${sendmail}
 11From: ${from}
 12To: ${to}
 13Subject: ${subject}
 14
 15${body}
 16EOF
 17
 18}
    

2017/09/07

AAC を MP3 に変換する

Mac では通常だとオーディオファイルは AAC 形式か ALAC 形式で保存していて、ファイルの拡張子は通常 "m4a" を利用している。
これらのファイルを一般的な mp3 形式に変換する場合、特に Mac では iTunes などの GUI アプリケーションを利用するのが普通なのだが、 多数のファイルを一括で変換する場合など GUI アプリケーションだと操作が面倒になる。
そこで、 AAC 形式のオーディオファイルを mp3 形式に変換するスクリプトを作ってみた。 オーディオファイルを mp3 形式に変換するコマンドはいくつも存在するが、今回は Mac で導入が簡単な lame を利用する。 lame は AAC 形式や ALAC 形式には対応していないので、こちらも Mac で導入が簡単な faad を利用して AAC / ALAC 形式のオーディオファイルを 一度 wav 形式に変換してから lame を利用して mp3 形式に変換する。

利用の前提として faad と lame が必要なので、それぞれを MacPorts や Homebrew によりインストールする。

$ sudo port install faad2 lame
:
:
--->  Fetching archive for faad2
--->  Attempting to fetch faad2-2.7_0.darwin_16.x86_64.tbz2 from http://kmq.jp.packages.macports.org/faad2
--->  Attempting to fetch faad2-2.7_0.darwin_16.x86_64.tbz2.rmd160 from http://kmq.jp.packages.macports.org/faad2
--->  Installing faad2 @2.7_0
--->  Activating faad2 @2.7_0
--->  Cleaning faad2
--->  Updating database of binaries
--->  Scanning binaries for linking errors
--->  No broken files found.
    

次に PATH が通ったディレクトリに以下のスクリプトを設置して適切な実行権限を付与しておく。
このスクリプトでは AAC / ALC 形式と mp3 形式が混在している事を想定しており、 mp3 ファイルの場合はそのままコピーする様にしている。

  1#!/bin/sh
  2# mp3 ファイルを格納するためのディレクトリ
  3top="${HOME}/mp3"
  4
  5find . | while read line
  6do
  7    if [ -d "${line}" ]
  8    then
  9        mkdir -p "${top}/${line}"
 10    else
 11        dst=${top}/$(echo "${line}" | sed 's/m4a/mp3/')
 12        if [ "${line##*.}" = "m4a" ]
 13        then
 14            wav=${top}/$(echo "${line}" | sed 's/m4a/wav/')
 15            faad -q "${line}" -o "${wav}"
 16            lame --quiet -h -b 192 "${wav}" "${dst}"
 17            rm "${wav}"
 18        else
 19            cp "${line}" "${dst}"
 20        fi
 21    fi
 22done
    
準備ができたらオーディオファイルが格納されているディレクトリでスクリプトを実行すれば mp3 形式のオーディオファイルが作成される。
以下の例ではファイル名を convert.sh として ${HOME}/bin 以下に設置している。
$ vi $HOME/bin/convert.sh
$ chmod 755 $HOME/bin/convert.sh
$ cd $HOME/Music/iTunes/iTunes\ Music
$ convert.sh
    


Copyright © 2008-2020 Mitzyuki IMAIZUMI. All rights reserved.