#!/bin/bash
# Usage:
# History:
#
thread=$1 #设置线程数,在这里所谓的线程,其实就是几乎同时放入后台(使用&)执行的进程。
if [ "$1"x == ""x ] || [ "$2"x == ""x ]; then
echo "2 args: ./cmdb.sh thread cmdbfile"
exit 0
fi
CMDB_FILE_NAME=$2
RULES_FILE=rule.txt
rm -rf error correct no_rule
mkdir error
mkdir correct
mkdir no_rule
tmp_fifofile=/tmp/$.fifo #脚本运行的当前进程ID号作为文件名
mkfifo $tmp_fifofile #新建一个随机fifo管道文件
exec 6<>$tmp_fifofile #定义文件描述符6指向这个fifo管道文件
rm $tmp_fifofile #清空管道内容
#定义一个函数做为线程(子进程)
function func()
{
id=`echo $id | sed "s/"",/"kong",/g"` #将类型为空的替换为 kong
TYPE=`echo $id | awk -F '["]' '{print $10}'` #cmdb中查到的网络类型,必须处理为空的类型
NET=`echo $id | awk -F '["]' '{print $6}' |awk -F '[.]' '{print $1}'` #IP地址前8位
if [ "$NET"x = "10"x ]; then
NET=`echo $id | awk -F '["]' '{print $6}' |awk -F '[.]' '{print $1"."$2}'` #10开头的取前16位
if [ "$NET"x = "10.62"x ] || [ "$NET"x = "10.63"x ] || [ "$NET"x = "10.64"x ]; then
NET=`echo $id | awk -F '["]' '{print $6}' |awk -F '[.]' '{print $1"."$2"."$3}'` #10.62/63/64开头的取前24位
fi
fi
((++$i))
echo "$i - $NET - $TYPE"
RULE=`grep "^$NET\." $RULES_FILE | awk '{print $2}'` #对应规则
if [ "$RULE"x = ""x ]; then
TMP=`echo $NET | awk -F '[.]' '{print $1}'`
if [ "$TMP"x = "10"x ]; then
RULE=$TYPE
echo $id >>no_rule/$NET.csv
else
RULE="外网" #规则中没有包含的且不为私有地址的统一作为外网处理,因此公网IP规则不需要写进规则文件
fi
fi
if [ "$RULE"x != "$TYPE"x ]; then #如果查到的类型和对应规则不符,则输出
echo $id >>error/$NET.csv
echo $id |sed "s/$TYPE/$RULE/g" >>correct/$NET.csv
fi
sleep 3
}
# for循环 往 fifo管道文件中写入$thread个空行
for ((i=0;i<$thread;i++));do
echo
done >&6
#从cmdb.csv中读取
i=1
while read id;do
read -u6 #从文件描述符6中读取行(实际指向fifo管道)
{
func
echo >&6 #再次往fifo管道文件中写入一个空行
} &
# {} 这部分语句被放入后台作为一个子进程执行,所以不必每次等待3秒后执行
#下一个,这部分的func几乎是同时完成的,当fifo中thread个空行读完后 while循环
# 继续等待 read 中读取fifo数据,当后台的thread个子进程等待3秒后,按次序
# 排队往fifo输入空行,这样fifo中又有了数据,while循环继续执行
((i++))
done < $CMDB_FILE_NAME #从cmdb file中读取数据
wait #等到后台的进程都执行完毕
exec 6>&- ##删除文件描述符6
exit 0
|