今天把这段时间学习完shell后完成工作上的一个小案件整理了一下,分享给大家!
说来也巧了,作为一个刚刚毕业半年的菜鸟,进入公司后,听公司的大牛推荐学习linux–”鸟哥的私房菜“,基本上是从去年8月份开始到了今年的1月份,基本上是把基础篇看完了,开始了解shell脚本的相关知识。刚好公司有了一个shell脚本的案件给我了,时间上也没有多紧。然后就一边学习一边开始做,虽然中途客户反映先前的业务逻辑有问题耽搁了两周,但总算是到最后完成了,自己学习的东西能用到很开心,今天闲了,把代码整理了一下,分享给大家
具体是这样:
要求是写一个shell脚本,安装要求查询数据,将符合条件的数据按照客户给定的xml样式进行组装,然后加入到crontab中,定时执行通过scp或者ftp放到客户服务器上。
具体实现步骤:
一、编写生成xml文档的代码
#! /bin/bash
# filename: create_xml.sh
# create_wangxb_20150123
#
# 从外部传入的第一个参数作为xml的文件名
outfile=$1
# xml中的缩进位
tabs=0
# ++++++++++++++++++++++++++++
# 组装一个节点,输出到文件
# 说一说传参数时的这几个区别:假如有下面这个脚本执行的命令
# /path/to/scriptname opt1 opt2 opt3 opt4
# $0: 的值是默认是脚本的名字,从$1-$4 开始就是参数的值
# $# :代表后接的参数『个数』
# $@ :代表『 "$1" "$2" "$3" "$4" 』之意,每个变量是独立的(用双引号括起来);
# $* :代表『 "$1c$2c$3c$4" 』,其中 c 为分隔字节,默认为空白键, 所以本例中代表『 "$1 $2 $3 $4" 』之意。
# 在shell中我们可以也可以使用${}包含变量名,来调用变量
# ++++++++++++++++++++++++++++
put(){
echo '<'${*}'>' >> $outfile
}
# 这里也是输出一个xml的节点,只是比上面的节点有更多的设置
# ${@:2} 的意思:它的值就是由第二个参数开始到最后一个参数,为什么要这样?有时可能你的第二个参数中有空格,shell接受参数是以空格计算的
put_tag() {
echo '<'$1'>'${@:2}'</'$1'>' >> $outfile
}
# 同样是一个输出节点函数,但是添加了cdata,防止特殊字符造成xml解析失败
put_tag_cdata() {
echo '<'$1'><![cdata['${@:2}']]></'$1'>' >> $outfile
}
put_head(){
put '?'${1}'?'
}
# 这是一个缩进的算法,自行理解
out_tabs(){
tmp=0
tabsstr=""
while [ $tmp -lt $((tabs)) ]
do
tabsstr=${tabsstr}'\t'
tmp=$((tmp+1))
done
echo -e -n $tabsstr >> $outfile
}
tag_start(){
out_tabs
put $1
tabs=$((tabs+1))
}
tag() {
out_tabs
if [ "$1" == 0 ]
then
put_tag $2 $(echo ${@:3})
elif [ "$1" == 1 ]
then
put_tag_cdata $2 $(echo ${@:3})
fi
}
tag_end(){
tabs=$((tabs-1))
out_tabs
put '/'${1}
}
这里有一些基础知识:
关于参数:
假如有下面这个脚本执行的命令
/path/to/scriptname opt1 opt2 opt3 opt4
$0: 的值是默认是脚本的名字,从$1-$4 开始就是参数的值
$# :代表后接的参数『个数』
$@ :代表『 "$1" "$2" "$3" "$4" 』之意,每个变量是独立的(用双引号括起来);
$* :代表『 "$1c$2c$3c$4" 』,其中 c 为分隔字节,默认为空白键, 所以本例中代表『 "$1 $2 $3 $4" 』之意。
在shell中我们可以也可以使用${}包含变量名,来调用变量
二、从数据库查数据利用上面的函数,制作xml文件
#!/bin/bash
# filename: ts_xml.sh
# create_wangxb_20150126
#
path=/u01/app/oracle/product/10.2.0/db_1/bin:/usr/kerberos/bin:/usr/local/bin:/bin:/usr/bin:/opt/dell/srvadmin/bin:/home/p3s_batch/tools:/home/p3s_batch/bin
export path
# database account information file
source ~/.p3src
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# set some variable
# xmlscript: 脚本的绝对路径
# matching_result_xml: xml_1的文件名
# xml_func_file: 生成xml函数文件路径
# matching_result_query_data: sqlplus 查出数据保存的零时文件
# matching_result_query_sql: sqlplus 查询的sql语句
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# 下面是一些基础的设置
export xmlscript=/usr/p3s/batch/jaaa_match/tmp_xa_wangxb
xml_dir="$xmlscript/xmldata"
xml_func_file="xml_func.sh"
matching_result_xml="matching_result_"$(date '+%y%m%d_%h%m%s')".xml"
matching_result_query_data="matching_result_query_data.tmp"
matching_result_query_sql="matching_result_query.sql"
client_list_xml="client_list_"$(date '+%y%m%d_%h%m%s')".xml"
client_list_query_data="client_list_query_data.tmp"
client_list_query_sql="client_list_query.sql"
# add_wangxb_20150225
if [ ! -d "$xml_dir" ];
then
mkdir $xml_dir
fi
#+++++++++++++++++++++++++++
# modify_wangxb_20150224
# check for temporary file
#+++++++++++++++++++++++++++
if [ -e "$xml_dir/$matching_result_xml" ];
then
rm -f $xml_dir/$matching_result_xml
fi
if [ -e "$xmlscript/$matching_result_query_data" ];
then
matching_result_query_data="matching_result_query_data_"$(date '+%y%m%d%h%m%s')".tmp"
fi
#+++++++++++++++++++++++++++++++++++++++++++++++++
# add_wangxb_20150225
# check system time, choice query time period
# 这是是根据crontab每天执行的时间,取得我们查询数据库时的where条件的时间区间
#+++++++++++++++++++++++++++++++++++++++++++++++++
sys_datetime=$(date '+%y%m%d%h')
first_chk_datetime="$(date '+%y%m%d')04"
second_chk_datetime="$(date '+%y%m%d')12"
third_chk_datetime="$(date '+%y%m%d')20"
# 由于服务器crontab是上面的时间,但是执行的shell比较多,在调用我这个shell的时候,不一定就是04:30 ,12:30, 20:30所以,这里的根据系统的时间判断时 范围给的比较宽
case $sys_datetime in
"$first_chk_datetime"|"$(date '+%y%m%d')05"|"$(date '+%y%m%d')06"|"$(date '+%y%m%d')07")
chk_start=$(date '+%y-%m-%d 21:00:00' -d '-1 day')
chk_end=$(date '+%y-%m-%d 04:29:59')
;;
"$second_chk_datetime"|"$(date '+%y%m%d')13"|"$(date '+%y%m%d')14"|"$(date '+%y%m%d')15")
chk_start=$(date '+%y-%m-%d 04:30:00')
chk_end=$(date '+%y-%m-%d 12:29:59')
;;
"$third_chk_datetime"|"$(date '+%y%m%d')21"|"$(date '+%y%m%d')22"|"$(date '+%y%m%d')23")
chk_start=$(date '+%y-%m-%d 12:30:00')
chk_end=$(date '+%y-%m-%d 20:59:59')
;;
*)
chk_start=$(date '+%y-%m-%d 00:00:00')
chk_end=$(date '+%y-%m-%d 23:59:59')
;;
esac
# modify_wangxb_20150310
# 下面的是做一个oracle数据库连接的测试,如果连接失败,后续代码不再执行,并且写入错误日志
$oracle_home/bin/sqlplus -s $orauser_web_pasdb << eof
set echo off
set feedback off
alter session set nls_date_format='yyyy-mm-dd:hh24:mi:ss';
select sysdate from dual;
quit
eof
if [ $? -ne 0 ]
then
echo "********** dbへのリンク己窃した **********"
exit
else
echo "********** dbへのリンクokです **********"
fi
# sqlplus就是oracle的一个客户端软件,具体使用方法可以问度娘,这里传入要执行的sql和参数,将结果 > 输出到指定文件
$oracle_home/bin/sqlplus -s $orauser_web_pasdb @$xmlscript/$matching_result_query_sql "$chk_start" "$chk_end" > $xmlscript/$matching_result_query_data
# create matching result's xml file
# add_wangxb_20150227
# 下面的算法就是将查出的数据进行分析,调用xml函数生成xml文件
source "$xmlscript/$xml_func_file" "$xml_dir/$matching_result_xml"
put_head 'xml version="1.0" encoding="utf-8"'
tag_start 'root'
if [ -s "$xmlscript/$matching_result_query_data" ];
then
datas=${xmlscript}/${matching_result_query_data}
#for res in $datas
while read res;
do
stock_id=$(echo $res | awk 'begin {fs="\\^\\*\\^"} {print $1}')
seirino=$(echo $res | awk 'begin {fs="\\^\\*\\^"} {print $2}')
match_flg=$(echo $res | awk 'begin {fs="\\^\\*\\^"} {print $3}')
unmatch_riyuu=$(echo $res | awk 'begin {fs="\\^\\*\\^"} {print $4}')
up_date_tmp=$(echo $res | awk 'begin {fs="\\^\\*\\^"} {print $5}')
up_date=$(echo $up_date_tmp | awk 'begin {fs="@"} {print $1 " " $2}')
tag_start 'matching'
tag 0 'stockid' ${stock_id:-""}
tag 0 'seirino' ${seirino:-""}
tag 0 'result' ${match_flg:-""}
tag 1 'reason' ${unmatch_riyuu:-""}
tag 0 'update_date' ${up_date:-""}
tag_end 'matching'
done < $datas
fi
tag_end 'root'
rm $xmlscript/$matching_result_query_data
# create client list's xml file
# add_wangxb_2015027
# 下面的是再生成一个xml文件,和上面一样
if [ -e "$xml_dir/$client_list_xml" ];
then
rm -f $xml_dir/$client_list_xml
fi
if [ -e "$xmlscript/$client_list_query_data" ];
then
client_list_query_data="client_list_query_data_"$(date '+%y%m%d%h%m%s')".tmp"
fi
$oracle_home/bin/sqlplus -s $orauser_mnd @$xmlscript/$client_list_query_sql > $xmlscript/$client_list_query_data
source "$xmlscript/$xml_func_file" "$xml_dir/$client_list_xml"
put_head 'xml version="1.0" encoding="utf-8"'
tag_start 'root'
if [ -s "$xmlscript/$client_list_query_data" ];
then
datas=${xmlscript}/${client_list_query_data}
#for res in $datas
while read res;
do
corporation_id=$(echo $res | awk 'begin {fs="\\^\\*\\^"} {print $1}')
corporation_name=$(echo $res | awk 'begin {fs="\\^\\*\\^"} {print $2}')
client_id=$(echo $res | awk 'begin {fs="\\^\\*\\^"} {print $3}')
client_print_name=$(echo $res | awk 'begin {fs="\\^\\*\\^"} {print $4}')
tag_start 'client'
tag 0 'corporation_id' ${corporation_id:-""}
tag 1 'corporation_name' ${corporation_name:-""}
tag 0 'client_id' ${client_id:-""}
tag 1 'client_print_name' ${client_print_name:-""}
tag_end 'client'
done < $datas
fi
tag_end 'root'
rm $xmlscript/$client_list_query_data
# add_wangxb_20150304
# convert xml file encoding
# 这是将xml文件进行转码,命令是iconv
if [ -e "$xml_dir/$matching_result_xml" ];
then
echo "********** matching_result.xmlファイルコ〖ドを啪垂し、**********"
iconv -f euc-jp -t utf-8 $xml_dir/$matching_result_xml -o $xml_dir/$matching_result_xml.utf-8
mv $xml_dir/$matching_result_xml.utf-8 $xml_dir/$matching_result_xml
fi
if [ -e "$xml_dir/$client_list_xml" ];
then
echo "********** client_list.xmlフィルコ〖ドを啪垂し、**********"
iconv -f euc-jp -t utf-8 $xml_dir/$client_list_xml -o $xml_dir/$client_list_xml.utf-8
mv $xml_dir/$client_list_xml.utf-8 $xml_dir/$client_list_xml
fi
# add_wangxb_20150304
# send the xml file to the destination server by ftp
#ftp_host="222.***.***.***"
#user="***"
#pass="***"
#ftp -i -n $ftp_host << eof
#user $user $pass
#cd /
#lcd $xml_dir/
#put $matching_result_xml
#put $client_list_xml
#quit
#eof
# test ftp
# 通过ftp将xml文件放到客户服务器上,ftp_host:客户服务器地址,user登录名,pass密码
ftp_host="***.***.***.***"
user="***"
pass="***"
dir="/upload"
ftp -i -n $ftp_host << eof
user $user $pass
cd /upload/
lcd $xml_dir/
put $matching_result_xml
put $client_list_xml
quit
eof
# save the program log file
yymm=$(date +'%y%m%d%h%m')
cp /tmp/create_xml.log /usr/p3s/batch/jaaa_match/tmp_xa_wangxb/logs/create_xml.log.$yymm
# send error log files into the admin mailbox
info_to_mail_1="**@**.co.jp"
info_to_mail_2="***@**.co.jp"
# nkf 日文转码的一个命令
title=$(echo "test" | nkf -j)
nkf -j < /tmp/create_xml.log | mail -s $title $info_to_mail_1 $info_to_mail_2
#exit
本来是用scp传送的,但是后面修改了,这里把自己为scp传送找到的一个,不用密码可立即登入的 ssh 用户
下面是执行的两个sql文件
set pagesize 0
set feedback off
set verify off
set echo off
set heading off
set timi off
set linesize 1000
set wrap off
select s.stockid|| '^*^' ||a.seri_no|| '^*^' ||a.match_flg|| '^*^' ||a.unmatch_riyuu|| '^*^' ||to_char(a.up_date,[email protected]:mi:ss') up_date from aaa_stock_db a left join senddataappraisalproto s on a.seri_no=s.seirino where a.up_date between to_date('&1','yyyy-mm-dd hh24:mi:ss') and to_date('&2','yyyy-mm-dd hh24:mi:ss') and a.del_flg=0 order by a.up_date desc;
exit
set pagesize 0
set feedback off
set verify off
set echo off
set heading off
set timi off
set linesize 1000
set wrap off
select a.corporation_id|| '^*^' ||a.corporation_name|| '^*^' ||b.client_id|| '^*^' ||(select client_print_name from client_master where client_id = b.client_id) as client_print_name from m_corporation_master a left join m_corporation_group b on (a.corporation_id = b.corporation_id) where a.del_flg=0 and b.del_flg=0;
exit
三、来看看效果
当然中间出现了许多bug,不过慢慢修改吗,兵来将挡,水来土掩,bug来了自己调么
就这样简单的整理一下,可能光这么写不够完整,但是,中间设计的知识也很多,不能展开了说,做个分享,大家有用到的时候也是个思路,具体的某些知识点可以用到了再去找资料了。
以上就是用shell脚本生成xml文件实例详解的详细内容。
