MAC(Medium/Media Access Control)地址,采用十六进制数表示,共六个字节(48位)。其中,前三个字节是由IEEE的注册管理机构RA负责给不同厂家分配的代码,后三个字节由各厂家自行指派给生产的适配器接口。
1.背景
IEEE在其官网上提供了已经分配出去的MAC地址及对应厂商的数据源供大家下载,遗憾的是直接下载下来的数据并不能很好满足我们的某些需求,于是需要对其进行简单的处理。
如下所示摘自IEEE官网提供的oui.txt的数据片段:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
OUI/MA-L Organization company_id Organization Address E0-43-DB (hex) Shenzhen ViewAt Technology Co.,Ltd. E043DB (base 16) Shenzhen ViewAt Technology Co.,Ltd. 9A,Microprofit,6th Gaoxin South Road, High-Tech Industrial Park, Nanshan, Shenzhen, CHINA. shenzhen guangdong 518057 CN 24-05-F5 (hex) Integrated Device Technology (Malaysia) Sdn. Bhd. 2405F5 (base 16) Integrated Device Technology (Malaysia) Sdn. Bhd. Phase 3, Bayan Lepas FIZ Bayan Lepas Penang 11900 MY 3C-D9-2B (hex) Hewlett Packard 3CD92B (base 16) Hewlett Packard 11445 Compaq Center Drive Houston 77070 US ... ... ... |
现在我们想要将其提取成如下“MAC|厂商”样式的数据:
1 2 3 |
E0-43-DB|Shenzhen ViewAt Technology Co.,Ltd. 24-05-F5|Integrated Device Technology (Malaysia) Sdn. Bhd. 3C-D9-2B|Hewlett Packard |
该怎么提取呢?
使用shell 脚本语言实现正则表达式提取出我们需要的字符串格式,并导入mysql数据库表中。
2.正则表达式匹配MAC地址
比如,形如E0-43-DB的MAC地址,有如下正则表达式可以实现对其匹配:
1 |
\([0-9a-fA-F]\{2\}-\)\{2\}[0-9a-fA-F]\{2\} |
分析E0-43-DB,其中红色部分和蓝色部分可以使用\([0-9a-fA-F]\{2\}-\)\{2\}进行匹配,最后一部分DB使用[0-9a-fA-F]\{2\}进行匹配。
其中,\是对()和{}的转义,\{2\}是重复前一项2次。
3.shell脚本实现
有了上述正则表达式,我们就可以对oui.txt文件中的所有具有形如E0-43-DB格式的行进行匹配了。比如,我们可以匹配出形如如下格式的数据:
1 2 3 |
E0-43-DB (hex) Shenzhen ViewAt Technology Co.,Ltd. 24-05-F5 (hex) Integrated Device Technology (Malaysia) Sdn. Bhd. 3C-D9-2B (hex) Hewlett Packard |
有了这些数据,再提取出第一列MAC地址和最后的厂商信息就完成目标啦,这里我们会用到grep和awk这些神器:
1 2 3 4 5 6 7 8 9 10 11 12 |
#!/bin/bash while read line do var=`echo $line | grep '\([0-9a-fA-F]\{2\}-\)\{2\}[0-9a-fA-F]\{2\}'` if [ -n "$var" ] then mac=`echo $var | awk '{print $1}'` cmp=`echo $var | awk -F "hex) " '{print $2}'` echo "$mac|$cmp" >> output.txt fi done < oui.txt |
其中:
(1)while语句的作用是从文件oui.txt中逐行读取字符串到变量line中:
1 2 3 4 |
while read line do done < oui.txt |
(2)if判断语句的作用是判断当前字符串变量var是否为空,-n表示不为空(-z表示为空)。
(3)awk默认分隔符是空格或tab键,选项-F是指定其分隔符。awk语句的使用可参考我的其他博文,通过上述shell脚本,最终将格式化后的内容输出到文件output.txt中:
1 2 3 4 5 |
E0-43-DB|Shenzhen ViewAt Technology Co.,Ltd. 24-05-F5|Integrated Device Technology (Malaysia) Sdn. Bhd. 3C-D9-2B|Hewlett Packard ... ... |
4.内容导入MySQL
而有些时候,我们的需求可能不仅仅如此,比如需要将上面导出的数据再导入数据库的表中,方便我们进行MAC地址的查找匹配。
对于MySQL而言,使用load data infile语句即可实现:
1 |
mysql> load data infile "/home/leo/output.txt" into table mac_company fields terminated by '|' optionally enclosed by '' lines terminated by '\n'(mac, company); |
查看前五行:
1 2 3 4 5 6 7 8 9 10 11 |
mysql> select * from mac_company limit 5; +----+----------+---------------------------------------------------+ | id | mac | company | +----+----------+---------------------------------------------------+ | 1 | E0-43-DB | Shenzhen ViewAt Technology Co.,Ltd. | | 2 | 24-05-F5 | Integrated Device Technology (Malaysia) Sdn. Bhd. | | 3 | 3C-D9-2B | Hewlett Packard | | 4 | 9C-8E-99 | Hewlett Packard | | 5 | B4-99-BA | Hewlett Packard | +----+----------+---------------------------------------------------+ 5 rows in set |
导入成功。
除了load data infile语句,还有一个工具实现了对load data infile语句的命令行接口,上面的导入语句等价于:
1 |
$ mysqlimport -uroot -p123456 --local --fields-terminated-by="|" --fields-enclosed-by="" --lines-terminated-by="\n" crashcourse /home/leo/output.txt |
需要说明的是:
(1)从文件output.txt导入到数据库表中之前,数据库中必须存在一个名为output的表。(这也是为什么语句中没有指定导入表的原因)
(2)–fields-enclosed- by默认是“”,–fields-terminated- by默认是Tab,–lines-terminated- by默认是newline