#!/bin/sh ######################################################################## # # MKZIPIDC_KENALL.SH # 日本郵便の郵便番号CSVから、オンライン用の辞書を作成(検索用) # # Written by shogo osawa on 2026-01-25 # # Usage : mkzipidc.sh [-f] # -f : サイト上のCSVファイルのタイムスタンプが、 # 今ある辞書ファイルより新しくても更新する # # 【出力】 # ・作成成功もしくはサイトのタイムスタンプが古いために作成する必要無 # しの場合、失敗したら以外 # ・成功時は辞書ファイルを更新する # ######################################################################## ######################################################################## # 初期設定 ######################################################################## readonly file_ZIPIDC="ken_all.txt" # 郵便番号辞書ファイルのパス readonly url_ZIPCSVZIP="https://www.post.japanpost.jp/zipcode/dl/oogaki/zip/ken_all.zip" readonly flag_SUEXECMODE=1 # サーバーがSUEXECモードで動いているなら1 # ファイルパス PATH="/usr/local/shellshock/bin:$PATH" ######################################################################## # 終了処理設定(終了前に一時ファイル削除) ######################################################################## exit_trap() { [ -n "${tmp_zipcsvzip:-}" ] && rm -f $tmp_zipcsvzip [ -n "${tmp_zipdic:-}" ] && rm -f $tmp_zipdic exit ${1:-0} } trap 'exit_trap' 0 1 2 3 13 14 15 ######################################################################## # エラー終了関数定義 ######################################################################## error_exit() { [ -n "$2" ] && echo "${0##*/}: $2" 1>&2 exit_trap $1 } ######################################################################## # テンポラリーファイル確保 ######################################################################## tmp_zipcsvzip=$(mktemp -t "${0##*/}.XXXXXX") [ $? -eq 0 ] || error_exit 1 'Failed to make temporary file #1' tmp_zipdic=$(mktemp -t "${0##*/}.XXXXXX") [ $? -eq 0 ] || error_exit 2 'Failed to make temporary file #2' ######################################################################## # メイン ######################################################################## # 引数チェック flag_FORCE=0 case "$1" in -f) flag_FORCE=1 ;; esac # Webアクセスコマンド存在チェック type curl >/dev/null 2>&1 || type wget >/dev/null 2>&1 || { error_exit 3 'No HTTP-GET/POST command found.' } # ZIP展開コマンド存在チェック type unzip >/dev/null 2>&1 || type gunzip >/dev/null 2>&1 || { error_exit 4 'No ZIP extractor command found.' } ######################################################################## # サイト上のファイルのタイムスタンプを取得 ######################################################################## timestamp_web=$( if type curl >/dev/null 2>&1; then curl -sI $url_ZIPCSVZIP else wget -S --spider $url_ZIPCSVZIP | sed 's/^ *//' fi | awk ' BEGIN { status = 0; d["Jan"]="01"; d["Feb"]="02"; d["Mar"]="03"; d["Apr"]="04"; d["May"]="05"; d["Jun"]="06"; d["Jul"]="07"; d["Aug"]="08"; d["Sep"]="09"; d["Oct"]="10"; d["Nov"]="11"; d["Dec"]="12"; } /^HTTP\// { status = $2; } /^Last-Modified:/i { gsub(/,/, "", $6); ts = sprintf("%04d%02d%02d%06d", $5, d[$4], $3, $6); } END { if ((status>=200) && (status<300) && (length(ts)==14)) { print ts; } else { print "NOT_FOUND"; } }' ) [ "$timestamp_web" != "NOT_FOUND" ] || error_exit 5 'The zipcode CSV file not found on the web' printf "%s\n" "$timestamp_web" | grep -Eq '^[0-9]{14}$' [ $? -eq 0 ] || timestamp_web=$(TZ=UTC date +%Y%m%d%H%M%S) ######################################################################## # 手元の辞書ファイルのタイムスタンプと比較し、更新必要性確認 ######################################################################## while [ $flag_FORCE -eq 0 ]; do [ -f "$file_ZIPIDC" ] || break timestamp_local=$(head -n 1 "$file_ZIPIDC" | awk '{print $NF}') printf "%s\n" "$timestamp_local" | grep -Eq '^[0-9]{14}$' || break [ "$timestamp_web" -gt "$timestamp_local" ] || break exit 0 done ######################################################################## # 郵便番号CSVデータファイル(zip形式)ダウンロード ######################################################################## if type curl >/dev/null 2>&1; then curl -s $url_ZIPCSVZIP > $tmp_zipcsvzip else wget -q -O - $url_ZIPCSVZIP > $tmp_zipcsvzip fi [ $? -eq 0 ] || error_exit 6 'Failed to download the zipcode CSV file' ######################################################################## # 郵便番号CSVデータファイル解凍 ######################################################################## if type unzip >/dev/null 2>&1; then unzip -p $tmp_zipcsvzip elif type gunzip >/dev/null 2>&1; then gunzip < $tmp_zipcsvzip 2>/dev/null || { error_exit 7 'No ZIP archive extractor found (unzip)' } else error_exit 8 'No ZIP archive extractor found (unzip or gunzip)' fi | ######################################################################## # 日本郵便 郵便番号-住所 CSVデータ (Shift_JIS) ######################################################################## if type iconv >/dev/null 2>&1; then iconv -c -f CP932 -t UTF-8 elif type nkf >/dev/null 2>&1; then nkf -w80 else error_exit 9 'No KANJI convertors found (iconv or nkf)' fi | ######################################################################## # 日本郵便 郵便番号-住所 CSVデータ (UTF-8変換) ######################################################################## awk -F, -v ts="$timestamp_web" ' BEGIN { print "# generated: " ts } { zip=$3 pref=$7 city=$8 town=$9 gsub(/"/,"",zip) gsub(/"/,"",pref) gsub(/"/,"",city) gsub(/"/,"",town) # ★ 都道府県 / 市区町村 / 町域 を空白区切りで出力 print zip, pref, city, town } ' | sed 's/ / /g' | sed 's/ *$//' | sort -u > $tmp_zipdic [ -s $tmp_zipdic ] || error_exit 10 'Failed to make the zipcode dictionary file' mv $tmp_zipdic $file_ZIPIDC [ "$flag_SUEXECMODE" -eq 0 ] || chmod go+r $file_ZIPIDC ######################################################################## # 正常終了 ######################################################################## exit 0