在
上一篇,那个Shell写好后,领导说,你的那个Shell只能监控到服务器本地指定目录文件的变化。不过当监控多台服务器上的文件变化,那么就需要部署多个脚本,比较麻烦。建议是,在数据库上创建一个表,记录需要监控的服务器,文件。程序自动扫描进行监控。
自己静下心来思考,觉得领导说的还是很有道理。在数据库上创建一张表,记录要监控的文件信息。方便维护。当需要添加要监控的文件,在数据库中添加一条记录,即可实现。数据库SQL代码如下:
-
-- Create table
-
create table TI_FILE_CHECK
-
(
-
FILE_ID NUMBER(16) not null,
-
SERVER_IP VARCHAR2(20) not null,
-
USER_NAME VARCHAR2(40) not null,
-
PASS_WORD VARCHAR2(40) not null,
-
PROJECT_NAME VARCHAR2(40) not null,
-
FILE_NAME VARCHAR2(100) not null,
-
LOCAL_SIZE NUMBER(16) not null,
-
LOCAL_TIME DATE not null,
-
FILE_PATH VARCHAR2(500) not null,
-
OS_TYPE VARCHAR2(1) default 0 not null,
-
RECV_PHONENUM VARCHAR2(20) not null,
-
IS_UP VARCHAR2(1) default 0 not null,
-
UP_SIZE NUMBER(16),
-
UP_TIME DATE,
-
REMARK VARCHAR2(500)
-
)
-
tablespace TBS_ITF_DAT1
-
pctfree 10
-
initrans 1
-
maxtrans 255
-
storage
-
(
-
initial 64K
-
next 1M
-
minextents 1
-
maxextents unlimited
-
);
-
-- Add comments to the table
-
comment on table TI_FILE_CHECK
-
is '文件监控表';
-
-- Add comments to the columns
-
comment on column TI_FILE_CHECK.FILE_ID
-
is '文件ID';
-
comment on column TI_FILE_CHECK.SERVER_IP
-
is '服务器IP';
-
comment on column TI_FILE_CHECK.USER_NAME
-
is '登陆服务器的用户名';
-
comment on column TI_FILE_CHECK.PASS_WORD
-
is '登陆服务器的密码';
-
comment on column TI_FILE_CHECK.PROJECT_NAME
-
is '程序名称';
-
comment on column TI_FILE_CHECK.FILE_NAME
-
is '文件名称';
-
comment on column TI_FILE_CHECK.LOCAL_SIZE
-
is '原始文件大小(在UNIX/LINUX操作系统上使用 ls -l 获取的文件的大小值)';
-
comment on column TI_FILE_CHECK.LOCAL_TIME
-
is '原始文件日期(在UNIX/LINUX操作系统上使用 ls -l 获取的文件日期的写入值)';
-
comment on column TI_FILE_CHECK.FILE_PATH
-
is '文件绝对路径(包含文件名)';
-
comment on column TI_FILE_CHECK.OS_TYPE
-
is '操作系统类型(0:AIX),现在只支持AIX系统,如果其他版本,请扩展Shell脚本程序';
-
comment on column TI_FILE_CHECK.RECV_PHONENUM
-
is '接收短信的号码';
-
comment on column TI_FILE_CHECK.IS_UP
-
is '文件是否更新:0:没有更新;1:文件已经更新';
-
comment on column TI_FILE_CHECK.UP_SIZE
-
is '更新后的大小(数据的来源是ls -l获取的最新值)';
-
comment on column TI_FILE_CHECK.UP_TIME
-
is '更新的日期(数据的来源是ls -l获取的最新值)';
-
comment on column TI_FILE_CHECK.REMARK
-
is '发送的短信内容';
-
-- Create/Recreate primary, unique and foreign key constraints
-
alter table TI_FILE_CHECK
-
add constraint PK_FILE_CHECK_FILE_ID primary key (FILE_ID)
-
using index
-
tablespace TBS_ITF_DAT1
-
pctfree 10
-
initrans 2
-
maxtrans 255
-
storage
-
(
-
initial 64K
-
next 1M
-
minextents 1
-
maxextents unlimited
-
);
我自己捋了捋,思路。首先在数据库上创建表,然后用一个程序读取要监控的数据,生成文件放到本地。读取数据库数据,生成文件。当时上网查了查资料,很多资料都是用shell脚本代码,通过sqlplus 里面的SQL查询语句。我觉得也可以,可是试了后,才发现不行。因为我需要的数据有一定的格式。方便下一步读取数据。最后为了完成数据的格式化。最终决定,写个java程序,用java程序读取数据库数据,生成数据文件。生成数据文件后,下一步操作,那就是使用Shell一次读取生成文件的一行数据,登陆到远程服务器上,查询哪个文件信息。想办法,将结果在返回到调用端。经过查找资料,在UNIX上有一个expect,可以模拟登陆,完成登陆完成查询操作。关于查询结果的返回,可以使用scp将数据copy到本地。当然了这些都需要调用端,通过传递参数实现。结果全部带回到本地后,下面就好弄了。通过循环读取文件,比较文件的日期是否发生了变化,这个当然了,使用awk。不过我们使用的AIX服务器,后面日期用的英文。因此自己编写shell函数,进行翻译操作。最终将发生变化的数据记录到文件中。然后用awk读取结果文件拼凑成SQL语句,提交到数据库。说了这么多,估计你也听的累了,先放上我写的Shell程序,代码如下:
-
#!/bin/sh
-
# 程序描述: 扫描数据库表中的数据,根据IP,用户名,密码,文件路径等信息
-
# 扫描文件的大小,日期是否发生了变化,如果变动,记录变动的信息。
-
# 作者: 程晓鹏
-
# 日期:2013.12.03
-
# 运行程序命令:nohup ./FileCheck.sh &
-
-
#监控程序所在的目录
-
FC_SOURCE_HOME=/ngbss/mddms/FileCheck
-
#监控程序处理结果备份目录
-
FC_RESULT_HOME=$FC_SOURCE_HOME/result
-
#监控程序,返回数据的临时目录
-
FC_TMP_HOME=$FC_SOURCE_HOME/tmp
-
-
#被比对的原始数据文件,以此文件做标准
-
FC_CHECK_FILENAME=CHECK_LIST.TXT
-
#经过程序处理,最终发生变化,记录结果的文件
-
FC_RESULT_FILENAME=RESULT_CHECKLIST.TXT
-
#根据结果文件,生成插入数据库的SQL文件
-
FC_SQL_FILENAME=SQL_CHECKLIST.TXT
-
-
#部署监控程序的IP
-
FC_IP=127.0.0.1
-
#部署监控程序的用户名
-
FC_USERNAME=peng
-
#部署监控程序的密码
-
FC_PASSWORD=abc_321
-
#连接SQLPLUS的信息
-
FC_SQLPLUS_INFO=sa/sa_123@db1
-
-
#睡眠时间(单位:秒)
-
FC_SLEEP_TIME=5
-
-
#获取更新的文件大小(参数1:文件的绝对路径, 参数2:操作系统的版本[0:为AIX])
-
function GetUpdateFileSize
-
{
-
if [ $2 -eq "0" ]; then
-
echo $(ReadFileSize_AIX_6_1 $1);
-
fi
-
}
-
-
#获取文件的更新时间(参数1:文件的绝对路径, 参数2:操作系统的版本[0:为AIX)
-
function GetFileUpdateTime
-
{
-
if [ $2 -eq "0" ]; then
-
echo $(ReadFileUpdateTime_AIX_6_1 $1);
-
fi
-
}
-
-
#获取文件大小[AIX操作系统支持的](参数1:文件的绝对路径)
-
function ReadFileSize_AIX_6_1
-
{
-
local result=`cat "$1" | awk '{print $5}'`; #文件大小
-
echo $result;
-
}
-
-
#获取文件的更新时间,AIX6.1支持的函数(参数为文件的绝对路径)
-
function ReadFileUpdateTime_AIX_6_1
-
{
-
local month=`cat "$1" | awk '{print $6}'`; #月
-
local day=`cat "$1" | awk '{print $7}'`; #日
-
local tmp=`cat "$1" | awk '{print $8}'`; #年,或者时间的字符串
-
-
local tmplen=`echo $tmp | awk '{print length($0)}'`; #长度
-
local v_year="";
-
local v_month="";
-
local v_day="";
-
local v_time="";
-
-
if [ $tmplen -gt 4 ]
-
then
-
v_year=$(GetCurrentYear); #当字符长度大于4,则该字段为时间,因此v_year赋值为当前所属的年份
-
v_time=$tmp; #ls命令中的时间
-
else
-
v_year=$tmp; #文件的年份
-
v_time="00:00"; #使用默认值
-
fi
-
-
v_month=$(ConvertMonthToNumber "$month");
-
v_day=$day;
-
echo $v_year-$v_month-$v_day $v_time:00; #返回的格式为yyyy-MM-dd hh:mm:ss
-
}
-
-
#将英文表示的月份变更为数字(01-12)
-
function ConvertMonthToNumber
-
{
-
local result="";
-
case $1 in
-
"Jan") result="01";;
-
"Feb") result="02";;
-
"Mar") result="03";;
-
"Apr") result="04";;
-
"May") result="05";;
-
"Jun") result="06";;
-
"Jul") result="07";;
-
"Aug") result="08";;
-
"Sep") result="09";;
-
"Oct") result="10";;
-
"Nov") result="11";;
-
"Dec") result="12";;
-
esac
-
-
echo $result;
-
}
-
-
#获取当前年份(4为数字)
-
function GetCurrentYear
-
{
-
echo `date +%Y`;
-
}
-
-
#获取当前日期,时间
-
function GetCurrentTime
-
{
-
echo `date +"%Y-%m-%d %T"`;
-
}
-
-
#画线操作,隔离日志
-
function PrintLine
-
{
-
echo "-------------------------------------------------------------------------------\n"
-
}
-
-
#将日期字符串,返回为日期的字符串,如'2010-11-29 14:38:00'
-
#返回值为:20101129143800
-
#此函数,主要是为了比较比较日期大小。将日期字符串,转化为int,进行比较
-
#(没办法 AIX 不支持 date -d,也只能采用变通的方法了)
-
function GetDateNumber
-
{
-
#下面执行的命令,其实很简单,就是将日期之间的'-',':',空格删除操作。
-
local result=`echo $1 | sed -e 's/-//g' | sed -e 's/ //g' | sed -e 's/://g'`;
-
echo $result;
-
}
-
-
#获取文件的记录数(参数为文件的全路径)
-
function GetFileLineCount
-
{
-
result=0;
-
if [ -f "$1" ]; then
-
result=`wc -l "$1" | awk '{print $1}'`;
-
fi
-
echo $result;
-
}
-
-
#清空文件内容
-
function ClearFileContent
-
{
-
if [ -f "$1" ]; then
-
cat /dev/null > "$1";
-
fi
-
}
-
-
#使用java程序,下载比对源CheckList文件
-
function DownLoadCheckListFile
-
{
-
cd $FC_SOURCE_HOME/ExportDataFile;
-
MYDIR=`pwd`;
-
CLASSPATH=$MYDIR;
-
for f in `find $MYDIR/lib -type f -name "*.jar"`
-
do
-
CLASSPATH=$CLASSPATH:$f; #加载java程序需要的classpath
-
done
-
-
java -Xmx256m -cp $CLASSPATH com.epro.client.ExportData "$FC_SOURCE_HOME" "$FC_CHECK_FILENAME";
-
}
-
-
#读取对比源,CheckList文件(参数为文件的全路径)
-
#每读一行,获取这条记录的最新信息,放到临时目录中
-
function ExportUpdateFile
-
{
-
cat $FC_SOURCE_HOME/$FC_CHECK_FILENAME | while read line
-
do
-
local fileID=`echo $line | awk '{print $1}'`; #文件ID
-
local ip=`echo $line | awk '{print $2}'`; #IP地址
-
local username=`echo $line | awk '{print $3}'`; #用户名
-
local password=`echo $line | awk '{print $4}'`; #密码
-
local filepath=`echo $line | awk '{print $10}'`; #文件路径
-
expect $FC_SOURCE_HOME/FileInfo.exp $ip $username $password $filepath $FC_IP $FC_USERNAME $FC_PASSWORD $FC_TMP_HOME $fileID; #调用expect查看文件的信息
-
done
-
}
-
-
#进行数据处理,使用$FC_CHECK_FILENAME作为比对源文件,和$FC_TMP_HOME目录下的最新文件信息做比较
-
#当发现比对源文件的文件大小,或者日期发现了变化,进行记录
-
#比对数据源的内容如下:(不含下一行的第一个字符'#')
-
#1 127.0.0.1 peng peng123 炫铃程序 CRBT.jar 13929 2010-11-29 14:38:00 /ngbss/otherapp/pengtest/CRBT/lib/CRBT.jar 18538305950 0
-
function DisposeData
-
{
-
$(ClearFileContent $FC_SOURCE_HOME/$FC_RESULT_FILENAME); #清空文件内容
-
cat $FC_SOURCE_HOME/$FC_CHECK_FILENAME | while read line
-
do
-
local lo_fileID=`echo $line | awk '{print $1}'`; #文件ID
-
local lo_ip=`echo $line | awk '{print $2}'`; #IP地址
-
local lo_projectname=`echo $line | awk '{print $5}'`; #项目程序名称
-
local lo_filename=`echo $line | awk '{print $6}'`; #文件名
-
local lo_size=`echo $line | awk '{print $7}'`; #比对源大小
-
local lo_date=`echo $line | awk '{print $8 " " $9}'`; #比对文件日期
-
local lo_fullpath=`echo $line | awk '{print $10}'`; #文件全路径
-
local lo_recvnum=`echo $line | awk '{print $11}'`; #接收短信的号码
-
local lo_os_type=`echo $line | awk '{print $12}'`; #操作系统的类型 0:AIX操作系统
-
-
#当临时文件中含有更新的文件时,进行时间,大小的比对操作
-
if [ -f $FC_TMP_HOME/$lo_fileID ]
-
then
-
local up_size=$(GetUpdateFileSize $FC_TMP_HOME/$lo_fileID $lo_os_type);
-
local up_time=$(GetFileUpdateTime $FC_TMP_HOME/$lo_fileID $lo_os_type);
-
local int_datelocal=$(GetDateNumber "$lo_date");
-
local int_dateup=$(GetDateNumber "$up_time");
-
if [ $int_dateup -gt $int_datelocal ]; then #当文件的最新日期,大于数据库记录的原始日期时
-
echo $lo_fileID $lo_ip $lo_projectname $lo_filename $up_size $up_time $lo_fullpath $lo_recvnum >> $FC_SOURCE_HOME/$FC_RESULT_FILENAME;
-
fi
-
fi
-
done
-
}
-
-
#构建SQL语句文件(参数为生成SQL文件的路径)
-
function BuildSqlFile
-
{
-
$(ClearFileContent $FC_SOURCE_HOME/$FC_SQL_FILENAME); #清空文件内容
-
if [ -f $FC_SOURCE_HOME/$FC_RESULT_FILENAME ]; then
-
#更新文件监控的信息
-
awk '{print "UPDATE ti_file_check SET is_up='\''1'\'', up_size="$5", up_time=to_date('\''"$6" "$7"'\'','\''yyyy-MM-dd hh24:mi:ss'\''), remark='\''[文件更新]:您好:主机:"$2",程序名称:"$3", 文件名:"$4", 已更新。 更新日期为:"$6" "$7", 文件大小:"$5",请知悉。'\'' WHERE file_id = "$1";"}' $FC_SOURCE_HOME/$FC_RESULT_FILENAME >> $FC_SOURCE_HOME/$FC_SQL_FILENAME;
-
#发送短信
-
awk '{print "INSERT INTO ucr_itf1.sms_out_tab(row_no, message, deal_flag, destaddr) VALUES(ucr_itf1.seq_sms_out.nextval, '\''[文件更新]:您好:主机:"$2",程序名称:"$3", 文件名:"$4", 已更新。 更新日期为:"$6" "$7", 文件大小:"$5",请知悉。'\'', '\''0'\'', '\''"$9"'\'');"}' $FC_SOURCE_HOME/$FC_RESULT_FILENAME >> $FC_SOURCE_HOME/$FC_SQL_FILENAME;
-
fi
-
}
-
-
#提交生成的SQl语句
-
function CommitSqlFile
-
{
-
if [ -f $FC_SOURCE_HOME/$FC_SQL_FILENAME ]; then
-
. /ngbss/mddms/.profile
-
cmd=`sqlplus $FC_SQLPLUS_INFO <
-
@$FC_SOURCE_HOME/$FC_SQL_FILENAME
-
commit;
-
exit;
-
EOF`;
-
fi
-
}
-
-
#开始运行(并打印相关的日志信息)
-
function run
-
{
-
echo $(PrintLine);
-
echo $(PrintLine);
-
echo $(GetCurrentTime) 调用java程序,开始进行读取数据库,生成$FC_SOURCE_HOME/$FC_CHECK_FILENAME;
-
DownLoadCheckListFile;
-
linecount=$(GetFileLineCount $FC_SOURCE_HOME/$FC_CHECK_FILENAME); #获取文件记录数
-
if [ $linecount -gt 0 ]; then
-
echo $(GetCurrentTime) 读取数据库,生成文件完成。
-
echo $(GetCurrentTime) 根据"$FC_SOURCE_HOME"/"$FC_CHECK_FILENAME"文件内容,开始进行获取文件当前的最新更新数据
-
ExportUpdateFile;
-
echo $(GetCurrentTime) 获取每个最新数据成功,文件存放在"$FC_TMP_HOME"目录下
-
echo $(GetCurrentTime) 开始进行文件比对操作
-
DisposeData;
-
echo $(GetCurrentTime) 文件比对操作完成
-
linecount=$(GetFileLineCount $FC_SOURCE_HOME/$FC_RESULT_FILENAME); #获取文件记录数
-
if [ $linecount -gt 0 ]; then
-
echo $(GetCurrentTime) 比较结果如下:
-
cat $FC_SOURCE_HOME/$FC_RESULT_FILENAME;
-
echo $(GetCurrentTime) 开始生成SQL文件"$FC_SQL_FILENAME"
-
BuildSqlFile;
-
echo $(GetCurrentTime) 生成SQL完成,SQL文件内容如下:
-
cat $FC_SOURCE_HOME/$FC_SQL_FILENAME;
-
echo $(GetCurrentTime) 将SQL文件中的数据,进行执行操作
-
CommitSqlFile;
-
echo $(GetCurrentTime) SQL文件执行成功
-
echo $(GetCurrentTime) 更新成功
-
strdate=`date +"%Y_%m%d_%H%M%S"`; #当前日期字符串 2013_1210_085503
#进行结果备份操作
cp $FC_SOURCE_HOME/$FC_RESULT_FILENAME $FC_RESULT_HOME/$FC_RESULT_FILENAME.$strdate;
cp $FC_SOURCE_HOME/$FC_SQL_FILENAME $FC_RESULT_HOME/$FC_SQL_FILENAME.$strdate;
else
echo $(GetCurrentTime) 没有文件进行更新
fi
else
echo $(GetCurrentTime) 数据库中,没有要进行比对的数据
fi
}
while true
do
run;
sleep $FC_SLEEP_TIME; #进行休眠后,继续运行
done
为了方便,编写了一个方法,记录一些日志。也就是上面的run方法了。因为监控程序要不停的运行,运行完成后,休眠一段时间后,继续运行。
代码中,登陆到远程服务器上,通过调用expect,我们可以看到后面传递了很多参数,我编写的FileInfo.exp文件,代码如下:
-
#!/usr/bin/expect -f
-
-
# 程序描述:登录到远程主机,进行文件的查询操作,
-
# 并将结果返回到,调用的主机上
-
# 作者:程晓鹏
-
# 日期:2013.12.04
-
-
#连接的远程主机IP
-
set ipaddress [lindex $argv 0]
-
#连接远程主机的用户名
-
set username [lindex $argv 1]
-
#连接远程主机的密码
-
set passwd [lindex $argv 2]
-
#查询远程主机,文件的路径
-
set filepath [lindex $argv 3]
-
-
#将文件scp到目的地的相关参数
-
#文件返回的IP
-
set recv_ip [lindex $argv 4]
-
#文件返回所用的用户名
-
set recv_username [lindex $argv 5]
-
#文件返回所用的密码
-
set recv_password [lindex $argv 6]
-
#文件返回的目录
-
set recv_path [lindex $argv 7]
-
#文件返回的文件名
-
set recv_filename [lindex $argv 8]
-
set timeout 1
-
#进行登录
-
spawn ssh $username@$ipaddress
-
expect {
-
"yes/no" { send "yes\r";exp_continue }
-
#模拟输入密码,进行远程主机的登陆
-
"password:" { send "$passwd\r" }
-
}
-
expect "*from*"
-
#进行查询操作,将结果存入临时文件中
-
send "LANG=en_US; ls -l $filepath > /tmp/FileCheck.tmp\r"
-
#进行远程copy操作
-
send "scp /tmp/FileCheck.tmp $recv_username@$recv_ip:$recv_path/$recv_filename\r"
-
expect {
-
"yes/no" { send "yes\r";exp_continue }
-
#模拟输入密码
-
"password:" { send "$recv_password\r" }
-
}
-
expect eof
写的注释,比较多,就不解释了。当然了启动这个程序,也很简单使用nohup命令即可完成。对了方便停掉文件监控程序,也写了一个简单的Shell脚本,代码如下:
-
#!/bin/sh
-
u=`whoami`
-
-
ps -ef|grep "$u"|grep FileCheck.sh|grep -v grep|awk '{print $2}' >a.pid
-
for pid in `cat a.pid`
-
do
-
kill -9 $pid
-
done
-
echo "kill FileCheck done!"
文件监控启动后,我们使用nohup进行启动,因此会在当前目录下生成一个nohup.out文件,这里面记录了相关的日志信息,方便以后核对。
1.当文件发生变化时,日志会出现如下的内容:
2.正常的监控,没有文件发生变化,输出的日志内容如下:
3.最后一种就是,读取数据库没有要比对的文件,输出的日志内容如下:
最后,当想程序对文件进行监控,其实也很简单。就是更新local_size,local_time为最新的大小。别忘了is_up字段更新为'0';
最后附上我这个程序所有的文件代码。
FileCheck.rar ExportDataFile.rar
阅读(5708) | 评论(0) | 转发(0) |