計算問題が嫌いなので作ってみました。ただこれを使うとあまりサブネット計算の学習にはならないという問題を抱えています。
Ping-tのサブネットの計算問題で試してみて合っていたので、多分問題ないと思います。
32bit値のところで参考にさせていただきました。
[@harasou@github シェルスクリプトで IPアドレス計算] (http://qiita.com/harasou@github/items/5c14c335388f70e178f5 "シェルスクリプトで IPアドレス計算")
基本的に10進数のIPアドレスを入れて使う用途になっていますが、一応2進数表記から10進数表記に変換することもできます。
###色々と問題がありましたので下の方に修正版を追記してあります。
str = ARGV[0]
if str.match(/(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/) then
num = str.split(".")
#入力したIPアドレスの32Bit値を保管
@hom = (num[0].to_i << 24) + (num[1].to_i << 16) + (num[2].to_i << 8) + (num[3].to_i)
#2進数表記に変換
num.each_with_index do |n, count|
if count == 3
printf("%08d\n", "#{n.to_i.to_s(2)}")
break
end
@z = printf("%08d.","#{n.to_i.to_s(2)}")
end
puts "ネットワークの計算をしますか?"
puts "計算する場合はCIDR値を入力してください。"
print "==> "
cidr = STDIN.gets.chomp
#保管している32Bit値から論理和を計算
exit unless cidr.match(/[1-31]/)
cidr32 = (( 0xFFFFFFFF ^ ((2 ** (32-cidr.to_i)-1) )))
nwaddr = cidr32 & @hom
puts "ネットワークアドレス"
printf "%d.%d.%d.%d\n", (nwaddr >> 24), ((nwaddr >> 16) & 0xFF), ((nwaddr >> 8) & 0xFF), (nwaddr & 0xFF)
#ネットワークアドレスの排他的論理和と論理和
puts "ブロードキャストアドレス"
broad = ((cidr32 ^ 0xFFFFFFFF) | @hom)
printf "%d.%d.%d.%d\n", (broad >> 24), ((broad >> 16) & 0xFF), ((broad >> 8) & 0xFF), (broad & 0xFF)
elsif str.match(/([01]{1,8})\.([01]{1,8})\.([01]{1,8})\.([01]{1,8}$)/) then
num = str.split(".")
num.each_with_index do |n, count|
m = n.to_i(2)
if count == 3
puts "#{m}"
break
end
print "#{m}."
end
end
#使い方
引数に10進のIPアドレス。CIDRの確認で止まるので自分で考えてみたりするもよし・・。
$ ruby subnet2.rb 210.150.30.10
11010010.10010110.00011110.00001010
ネットワークの計算をしますか?
計算する場合はCIDR値を入力してください。
==> 28
ネットワークアドレス
210.150.30.0
ブロードキャストアドレス
210.150.30.15
ネットワーク計算が不要なら1〜31以外の数字でも空エンターでも叩くとEXITします。
$ ruby subnet2.rb 192.168.24.133
11000000.10101000.00011000.10000101
ネットワークの計算をしますか?
計算する場合はCIDR値を入力してください。
==>
上の2個を例にして2進数表記からの変換
$ ruby subnet2.rb 11010010.10010110.00011110.00001010
210.150.30.10
$ ruby subnet2.rb 11000000.10101000.00011000.10000101
192.168.24.133
こんな感じです。
はっ!スクリプトを書きだした前半と後半でprintfの記述の仕方が変わっている!
Σ( ̄ロ ̄lll)がびーん
##2015/03/17 追記
@scivola さん、@riocampos さん
いつもありがとうございます。
指摘いただいた間違い部分と組み込み系のメソッドの利用部分を使って修正してみました。
みましたというかモノマネですが^_^;
長くなりますが比較用のコメントアウトVerと、スッキリVerの2個載せます。
###修正Ver(比較用コメントアウトのみ)
str = ARGV[0]
case str
when /(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/
#nums = str.split(".")
nums = [$1, $2, $3, $4].map(&:to_i)
#IPアドレスの最終確認
#nums.each do |x|
# if x.to_i > 255
# puts "不正な入力です。"
# exit
# end
#end
if nums.any? { |x| x.to_i > 255 }
puts "不正な入力です。"
exit
end
#入力したIPアドレスの32Bit値を保管
#p @hom = (nums[0].to_i << 24) + (nums[1].to_i << 16) + (nums[2].to_i << 8) + (nums[3].to_i)
@hom = nums.inject{|r, x| r * 256 + x}
#2進数表記に変換
puts nums.map{|x| format('%08b', x)}.join('.')
#2進数表記に変換
#nums.each_with_index do |n, count|
# if count == 3
# printf("%08d\n", "#{n.to_i.to_s(2)}")
# break
# end
# printf("%08d.","#{n.to_i.to_s(2)}")
#end
puts "ネットワークの計算をしますか?"
puts "計算する場合はCIDR値を入力してください。"
print "==> "
cidr = STDIN.gets.chomp
#保管している32Bit値から論理和を計算
exit unless cidr.match(/\A\d+\z/) && (1..31).include?(cidr.to_i)
cidr32 = (( 0xFFFFFFFF ^ ((2 ** (32-cidr.to_i)-1) )))
nwaddr = cidr32 & @hom
puts "ネットワークアドレス"
#printf "%d.%d.%d.%d\n", (nwaddr >> 24), ((nwaddr >> 16) & 0xFF), ((nwaddr >> 8) & 0xFF), (nwaddr & 0xFF)
puts [24, 16, 8, 0].map{|n| (nwaddr >> n) & 0xFF}.join('.')
#ネットワークアドレスの排他的論理和と論理和
puts "ブロードキャストアドレス"
broad = ((cidr32 ^ 0xFFFFFFFF) | @hom)
#printf "%d.%d.%d.%d\n", (broad >> 24), ((broad >> 16) & 0xFF), ((broad >> 8) & 0xFF), (broad & 0xFF)
puts [24, 16, 8, 0].map{|n| (broad >> n) &0xFF}.join('.')
when /([01]{1,8})\.([01]{1,8})\.([01]{1,8})\.([01]{1,8}$)/
#2進数表記から10進数表記に変換
puts nums = [$1, $2, $3, $4].map{|s| s.to_i(2)}.join('.')
#2進数表記から10進数表記に変換
#nums = str.split(".")
#nums.each_with_index do |n, count|
# m = n.to_i(2)
# if count == 3
# puts "#{m}"
# break
# end
# print "#{m}."
#end
end
###スッキリVer
str = ARGV[0]
case str
when /(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/
nums = [$1, $2, $3, $4].map(&:to_i)
#IPアドレスの最終確認
if nums.any? { |x| x.to_i > 255 }
puts "不正な入力です。"
exit
end
#入力したIPアドレスの32Bit値を保管
@hom = nums.inject{|r, x| r * 256 + x}
#2進数表記に変換
puts nums.map{|x| format('%08b', x)}.join('.')
puts "ネットワークの計算をしますか?"
puts "計算する場合はCIDR値を入力してください。"
print "==> "
cidr = STDIN.gets.chomp
#保管している32Bit値から論理和を計算
exit unless cidr.match(/\A\d+\z/) && (1..31).include?(cidr.to_i)
cidr32 = (( 0xFFFFFFFF ^ ((2 ** (32-cidr.to_i)-1) )))
nwaddr = cidr32 & @hom
puts "ネットワークアドレス"
puts [24, 16, 8, 0].map{|n| (nwaddr >> n) & 0xFF}.join('.')
#ネットワークアドレスの排他的論理和と論理和
puts "ブロードキャストアドレス"
broad = ((cidr32 ^ 0xFFFFFFFF) | @hom)
puts [24, 16, 8, 0].map{|n| (broad >> n) &0xFF}.join('.')
when /([01]{1,8})\.([01]{1,8})\.([01]{1,8})\.([01]{1,8}$)/
puts nums = [$1, $2, $3, $4].map{|s| s.to_i(2)}.join('.')
end
###不具合の例
正規表現が間違っており、おかしなものが入った場合はEXITと思って書いていましたがこんなのが通ってしまっていました。
計算する場合はCIDR値を入力してください。
==> 2222
subnet2.rb:29:in `^': Rational can't be coerced into Rational (TypeError)
from subnet2.rb:29:in `<main>'
もういっちょは何も入れずでエラーが。
$ ruby subnet2.rb
subnet2.rb:6:in `<main>': undefined method `match' for nil:NilClass (NoMethodError)
などなど。