マイナンバーチェッカー用シェルawkスクリプト
先日は、仕様に基づいたマイナンバーを列挙するシェルのワンライナーを書いた。危険シェル芸ではないつもりだが、パソコンに高負荷をかけるため要注意なワンライナーではある。
これとは別に、12桁の数字がマイナンバーの仕様に合っているかを確認するためのシェルスクリプトを作ってみる。
今回も下記のチェックデジット計算についてのページを参考にする。
実行環境
今回もMacというかOSX Yosemiteで実行している。awkやsedはOS標準のものでもGNU版でも可。LinuxやFreeBSDでも動作すると思われる。
最初のシェルスクリプト
ということで最初に考えたシェルスクリプトがこちら。ファイル名をmynumber_checker.sh
をしておいた。
真・マイナンバーシェル芸に比べて処理が複雑になっているが、これは入力される数値が12桁以外の場合を考慮した結果だ。
mynumber_checker.sh
#!/bin/sh # マイナンバーチェッカー mynumber_checker.sh # # 標準入力から12桁の数値テキストデータを入力。 # 複数行可。フィルタとして動作する。 # 数値以外のデータ入力は想定していない。 # # チェックデジットの計算を基に、下記のようにOKかNGを判定して出力する。 # 12桁以外の数値の場合は、行頭にNG: をつけて出力する。 # OK: 123456789018 # OK: 023456789013 # NG: 123456789019 # NG: 1 # NG: 1234567890123 # 空行を削除 sed '/^$/d' | # 一桁ずつ空白区切りのフィールドに分解 sed 's/./& /g' | # 桁数(つまりフィールド数)を第一フィールドに出力 # チェックデジットの計算をして第二フィールドに出力 awk '{print NF,($1*6+$2*5+$3*4+$4*3+$5*2+$6*7+$7*6+$8*5+$9*4+$10*3+$11*2)%11,$0}' | awk '$2<=1{$2=0;print $0}$2>1{$2=(11-$2);print $0}' | # 1:桁数 2.チェックデジット 3:1桁目の数値 4:2桁目の数値 ......... # 12桁でない場合は行頭にNG:を出力 awk '$1!=12{print "NG:",$0}$1==12{print}' | # 計算したチェックデジットと12桁目が不一致ならNG:を出力。一致すればOK:を出力。 awk '/^NG:/{print}!/^NG:/{if($2!=$14){print "NG:",$0}else{print "OK:",$0}}' | # 1:OK/NG 2:桁数 3.チェックデジット 4:1桁目の数値 5:2桁目の数値 ......... # 分解されたフィールドを連結する awk '{printf $1" ";for(i=4;i<=$2+3;i++)printf $i;print ""}' # 1:OK/NG 2:マイナンバーの数値
見ての通りawkの連結で処理をしている・・・が、こんなやり方でもいいじゃない!?一つのawkスクリプトにしてしまってもいいのだが・・・
Twitterリプライいただいた後に
と思っていたら、@ebanさんのこのつぶやきを参考にして考えたら、結局awk一発になった。シェルスクリプトというよりawk芸だコレ。1桁ずつ空白で区切る必要も無くなった。
@papiron
— eban (@eban) May 1, 2016
1つにまとめるとこんな感じですね。
mawk '{c=($1*6+$2*5+$3*4+$4*3+$5*2+$6*7+$7*6+$8*5+$9*4+$10*3+$11*2)%11}$12==(c<=1?0:(11-c))' FS=
出来たシェルスクリプト・・・というかawkワンライナーがこちら。空行削除はも無くてもいいか・・・
mynumber_checker.sh
#!/bin/sh awk '{c=($1*6+$2*5+$3*4+$4*3+$5*2+$6*7+$7*6+$8*5+$9*4+$10*3+$11*2)%11}NF!=12||$12!=(c<=1?0:(11-c)){print "NG: "$0}$12==(c<=1?0:(11-c)){print "OK: "$0}' FS=
もうawkスクリプトでもええがな。awkワンライナーが見にくいならこちらでも良い。
mynumber_checker.awk
#!/usr/bin/env awk -f BEGIN { FS="" } { c=($1*6+$2*5+$3*4+$4*3+$5*2+$6*7+$7*6+$8*5+$9*4+$10*3+$11*2)%11 } NF!=12 || $12!=(c<=1?0:(11-c)) { print "NG: "$0 } $12==(c<=1?0:(11-c)) { print "OK: "$0 }
実行例
ではデータを準備して実行してみる。こんな感じで行頭にOK:
かNG:
を付けて表示する。シェルスクリプトとawkスクリプト、どちらも結果は同じだ。
$ chmod +x mynumber_checker.sh $ chmod +x mynumber_checker.awk $ echo 123456789018 | ./mynumber_checker.sh OK: 123456789018 $ echo 123456789019 | ./mynumber_checker.awk NG: 123456789019 $ cat numbers 1 11 111 1111 11111 1234567890123 123456789010 123456789011 123456789012 123456789013 123456789014 123456789015 123456789016 123456789017 123456789018 123456789019 023456789013 $ cat numbers | ./mynumber_checker.sh NG: 1 NG: 11 NG: 111 NG: 1111 NG: 11111 NG: 1234567890123 NG: 123456789010 NG: 123456789011 NG: 123456789012 NG: 123456789013 NG: 123456789014 NG: 123456789015 NG: 123456789016 NG: 123456789017 OK: 123456789018 NG: 123456789019 OK: 023456789013
MacというかOSXの場合はgseqコマンドを使おう
$ gseq -w 0 999999999999 | head -n 30 | ./mynumber_checker.awk OK: 000000000000 NG: 000000000001 NG: 000000000002 NG: 000000000003 NG: 000000000004 NG: 000000000005 NG: 000000000006 NG: 000000000007 NG: 000000000008 NG: 000000000009 NG: 000000000010 NG: 000000000011 NG: 000000000012 NG: 000000000013 NG: 000000000014 NG: 000000000015 NG: 000000000016 NG: 000000000017 NG: 000000000018 OK: 000000000019 NG: 000000000020 NG: 000000000021 NG: 000000000022 NG: 000000000023 NG: 000000000024 NG: 000000000025 NG: 000000000026 OK: 000000000027 NG: 000000000028 NG: 000000000029