今天把这段时间学习完shell后完成工作上的一个小案件整理了一下,分享给大家!
说来也巧了,作为一个刚刚毕业半年的菜鸟,进入公司后,听公司的大牛推荐学习linux--”鸟哥的私房菜“,基本上是从去年8月份开始到了今年的1月份,基本上是把基础篇看完了,开始了解shell脚本的相关知识。刚好公司有了一个shell脚本的案件给我了,时间上也没有多紧。然后就一边学习一边开始做,虽然中途客户反映先前的业务逻辑有问题耽搁了两周,但总算是到最后完成了,自己学习的东西能用到很开心,今天闲了,把代码整理了一下,分享给大家
具体是这样:
要求是写一个shell脚本,安装要求查询数据,将符合条件的数据按照客户给定的xml样式进行组装,然后加入到crontab中,定时执行通过scp或者ftp放到客户服务器上。
具体实现步骤:
一、编写生成xml文档的代码
网上搜索了一篇博客:http://blog.csdn.net/dengzhaoqun/article/details/7262271 拿来学习了一下,感觉好用,自己就根据自己的实际情况修改了一下:
1 #! /bin/bash 2 # filename: create_xml.sh 3 # create_wangxb_20150123 4 # 5 # 从外部传入的第一个参数作为xml的文件名 6 outfile=$1 7 # xml中的缩进位 8 tabs=0 9 10 # ++++++++++++++++++++++++++++ 11 # 组装一个节点,输出到文件 12 # 说一说传参数时的这几个区别:假如有下面这个脚本执行的命令 13 # /path/to/scriptname opt1 opt2 opt3 opt4 14 # $0: 的值是默认是脚本的名字,从$1-$4 开始就是参数的值 15 # $# :代表后接的参数『个数』 16 # $@ :代表『 "$1" "$2" "$3" "$4" 』之意,每个变量是独立的(用双引号括起来); 17 # $* :代表『 "$1c$2c$3c$4" 』,其中 c 为分隔字节,默认为空白键, 所以本例中代表『 "$1 $2 $3 $4" 』之意。 18 # 在shell中我们可以也可以使用${}包含变量名,来调用变量 19 # ++++++++++++++++++++++++++++ 20 put(){ 21 echo '<'${*}'>' >> $outfile 22 } 23 24 # 这里也是输出一个xml的节点,只是比上面的节点有更多的设置 25 # ${@:2} 的意思:它的值就是由第二个参数开始到最后一个参数,为什么要这样?有时可能你的第二个参数中有空格,shell接受参数是以空格计算的 26 put_tag() { 27 echo '<'$1'>'${@:2}'</'$1'>' >> $outfile 28 } 29 # 同样是一个输出节点函数,但是添加了CDATA,防止特殊字符造成xml解析失败 30 put_tag_cdata() { 31 echo '<'$1'><![CDATA['${@:2}']]></'$1'>' >> $outfile 32 } 33 34 put_head(){ 35 put '?'${1}'?' 36 } 37 # 这是一个缩进的算法,自行理解 38 out_tabs(){ 39 tmp=0 40 tabsstr="" 41 while [ $tmp -lt $((tabs)) ] 42 do 43 tabsstr=${tabsstr}' ' 44 tmp=$((tmp+1)) 45 done 46 echo -e -n $tabsstr >> $outfile 47 } 48 49 tag_start(){ 50 out_tabs 51 put $1 52 tabs=$((tabs+1)) 53 } 54 55 tag() { 56 out_tabs 57 if [ "$1" == 0 ] 58 then 59 put_tag $2 $(echo ${@:3}) 60 elif [ "$1" == 1 ] 61 then 62 put_tag_cdata $2 $(echo ${@:3}) 63 fi 64 } 65 66 tag_end(){ 67 tabs=$((tabs-1)) 68 out_tabs 69 put '/'${1} 70 }
这里有一些基础知识:
关于参数:
假如有下面这个脚本执行的命令
/path/to/scriptname opt1 opt2 opt3 opt4
1 $0: 的值是默认是脚本的名字,从$1-$4 开始就是参数的值 2 $# :代表后接的参数『个数』 3 $@ :代表『 "$1" "$2" "$3" "$4" 』之意,每个变量是独立的(用双引号括起来); 4 $* :代表『 "$1c$2c$3c$4" 』,其中 c 为分隔字节,默认为空白键, 所以本例中代表『 "$1 $2 $3 $4" 』之意。 5 在shell中我们可以也可以使用${}包含变量名,来调用变量
关于 ${@:2} 这种形式的说明,我转载了一篇博客:http://www.cnblogs.com/wxb0328/p/4276751.html
二、从数据库查数据利用上面的函数,制作xml文件
1 #!/bin/bash 2 # filename: ts_xml.sh 3 # create_wangxb_20150126 4 # 5 6 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 7 export PATH 8 # Database account information file 9 source ~/.p3src 10 11 #++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 12 # set some variable 13 # XMLSCRIPT: 脚本的绝对路径 14 # MATCHING_RESULT_XML: xml_1的文件名 15 # XML_FUNC_FILE: 生成xml函数文件路径 16 # MATCHING_RESULT_QUERY_DATA: sqlplus 查出数据保存的零时文件 17 # MATCHING_RESULT_QUERY_SQL: sqlplus 查询的sql语句 18 #++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 19 # 下面是一些基础的设置 20 export XMLSCRIPT=/usr/p3s/batch/jaaa_match/tmp_xa_wangxb 21 XML_DIR="$XMLSCRIPT/xmldata" 22 XML_FUNC_FILE="xml_func.sh" 23 24 MATCHING_RESULT_XML="matching_result_"$(date '+%Y%m%d_%H%M%S')".xml" 25 MATCHING_RESULT_QUERY_DATA="matching_result_query_data.tmp" 26 MATCHING_RESULT_QUERY_SQL="matching_result_query.sql" 27 28 CLIENT_LIST_XML="client_list_"$(date '+%Y%m%d_%H%M%S')".xml" 29 CLIENT_LIST_QUERY_DATA="client_list_query_data.tmp" 30 CLIENT_LIST_QUERY_SQL="client_list_query.sql" 31 32 # add_wangxb_20150225 33 if [ ! -d "$XML_DIR" ]; 34 then 35 mkdir $XML_DIR 36 fi 37 38 #+++++++++++++++++++++++++++ 39 # modify_wangxb_20150224 40 # check for temporary file 41 #+++++++++++++++++++++++++++ 42 if [ -e "$XML_DIR/$MATCHING_RESULT_XML" ]; 43 then 44 rm -f $XML_DIR/$MATCHING_RESULT_XML 45 fi 46 47 if [ -e "$XMLSCRIPT/$MATCHING_RESULT_QUERY_DATA" ]; 48 then 49 MATCHING_RESULT_QUERY_DATA="matching_result_query_data_"$(date '+%Y%m%d%H%M%S')".tmp" 50 fi 51 #+++++++++++++++++++++++++++++++++++++++++++++++++ 52 # add_wangxb_20150225 53 # check system time, choice query time period 54 # 这是是根据crontab每天执行的时间,取得我们查询数据库时的where条件的时间区间 55 #+++++++++++++++++++++++++++++++++++++++++++++++++ 56 sys_datetime=$(date '+%Y%m%d%H') 57 first_chk_datetime="$(date '+%Y%m%d')04" 58 second_chk_datetime="$(date '+%Y%m%d')12" 59 third_chk_datetime="$(date '+%Y%m%d')20" 60 # 由于服务器crontab是上面的时间,但是执行的shell比较多,在调用我这个shell的时候,不一定就是04:30 ,12:30, 20:30所以,这里的根据系统的时间判断时 范围给的比较宽 61 case $sys_datetime in 62 "$first_chk_datetime"|"$(date '+%Y%m%d')05"|"$(date '+%Y%m%d')06"|"$(date '+%Y%m%d')07") 63 chk_start=$(date '+%Y-%m-%d 21:00:00' -d '-1 day') 64 chk_end=$(date '+%Y-%m-%d 04:29:59') 65 ;; 66 "$second_chk_datetime"|"$(date '+%Y%m%d')13"|"$(date '+%Y%m%d')14"|"$(date '+%Y%m%d')15") 67 chk_start=$(date '+%Y-%m-%d 04:30:00') 68 chk_end=$(date '+%Y-%m-%d 12:29:59') 69 70 ;; 71 "$third_chk_datetime"|"$(date '+%Y%m%d')21"|"$(date '+%Y%m%d')22"|"$(date '+%Y%m%d')23") 72 chk_start=$(date '+%Y-%m-%d 12:30:00') 73 chk_end=$(date '+%Y-%m-%d 20:59:59') 74 75 ;; 76 *) 77 chk_start=$(date '+%Y-%m-%d 00:00:00') 78 chk_end=$(date '+%Y-%m-%d 23:59:59') 79 80 ;; 81 esac 82 83 # modify_wangxb_20150310 84 # 下面的是做一个oracle数据库连接的测试,如果连接失败,后续代码不再执行,并且写入错误日志 85 $ORACLE_HOME/bin/sqlplus -s $ORAUSER_WEB_PASDB << EOF 86 set echo off 87 set feedback off 88 alter session set nls_date_format='YYYY-MM-DD:HH24:MI:SS'; 89 select sysdate from dual; 90 quit 91 EOF 92 if [ $? -ne 0 ] 93 then 94 echo "********** DBへのリンク己窃した **********" 95 exit 96 else 97 echo "********** DBへのリンクOKです **********" 98 fi 99 # sqlplus就是oracle的一个客户端软件,具体使用方法可以问度娘,这里传入要执行的sql和参数,将结果 > 输出到指定文件 100 $ORACLE_HOME/bin/sqlplus -s $ORAUSER_WEB_PASDB @$XMLSCRIPT/$MATCHING_RESULT_QUERY_SQL "$chk_start" "$chk_end" > $XMLSCRIPT/$MATCHING_RESULT_QUERY_DATA 101 102 103 # create matching result's xml file 104 # add_wangxb_20150227 105 # 下面的算法就是将查出的数据进行分析,调用xml函数生成xml文件 106 source "$XMLSCRIPT/$XML_FUNC_FILE" "$XML_DIR/$MATCHING_RESULT_XML" 107 put_head 'xml version="1.0" encoding="utf-8"' 108 tag_start 'ROOT' 109 if [ -s "$XMLSCRIPT/$MATCHING_RESULT_QUERY_DATA" ]; 110 then 111 datas=${XMLSCRIPT}/${MATCHING_RESULT_QUERY_DATA} 112 #for res in $datas 113 while read res; 114 do 115 stock_id=$(echo $res | awk 'BEGIN {FS="\^\*\^"} {print $1}') 116 seirino=$(echo $res | awk 'BEGIN {FS="\^\*\^"} {print $2}') 117 match_flg=$(echo $res | awk 'BEGIN {FS="\^\*\^"} {print $3}') 118 unmatch_riyuu=$(echo $res | awk 'BEGIN {FS="\^\*\^"} {print $4}') 119 up_date_tmp=$(echo $res | awk 'BEGIN {FS="\^\*\^"} {print $5}') 120 up_date=$(echo $up_date_tmp | awk 'BEGIN {FS="@"} {print $1 " " $2}') 121 tag_start 'MATCHING' 122 tag 0 'STOCKID' ${stock_id:-""} 123 tag 0 'SEIRINO' ${seirino:-""} 124 tag 0 'RESULT' ${match_flg:-""} 125 tag 1 'REASON' ${unmatch_riyuu:-""} 126 tag 0 'UPDATE_DATE' ${up_date:-""} 127 tag_end 'MATCHING' 128 done < $datas 129 fi 130 tag_end 'ROOT' 131 rm $XMLSCRIPT/$MATCHING_RESULT_QUERY_DATA 132 133 134 # create client list's xml file 135 # add_wangxb_2015027 136 # 下面的是再生成一个xml文件,和上面一样 137 if [ -e "$XML_DIR/$CLIENT_LIST_XML" ]; 138 then 139 rm -f $XML_DIR/$CLIENT_LIST_XML 140 fi 141 142 if [ -e "$XMLSCRIPT/$CLIENT_LIST_QUERY_DATA" ]; 143 then 144 CLIENT_LIST_QUERY_DATA="client_list_query_data_"$(date '+%Y%m%d%H%M%S')".tmp" 145 fi 146 147 148 $ORACLE_HOME/bin/sqlplus -s $ORAUSER_MND @$XMLSCRIPT/$CLIENT_LIST_QUERY_SQL > $XMLSCRIPT/$CLIENT_LIST_QUERY_DATA 149 150 source "$XMLSCRIPT/$XML_FUNC_FILE" "$XML_DIR/$CLIENT_LIST_XML" 151 put_head 'xml version="1.0" encoding="utf-8"' 152 tag_start 'ROOT' 153 if [ -s "$XMLSCRIPT/$CLIENT_LIST_QUERY_DATA" ]; 154 then 155 datas=${XMLSCRIPT}/${CLIENT_LIST_QUERY_DATA} 156 #for res in $datas 157 while read res; 158 do 159 corporation_id=$(echo $res | awk 'BEGIN {FS="\^\*\^"} {print $1}') 160 corporation_name=$(echo $res | awk 'BEGIN {FS="\^\*\^"} {print $2}') 161 client_id=$(echo $res | awk 'BEGIN {FS="\^\*\^"} {print $3}') 162 client_print_name=$(echo $res | awk 'BEGIN {FS="\^\*\^"} {print $4}') 163 tag_start 'CLIENT' 164 tag 0 'CORPORATION_ID' ${corporation_id:-""} 165 tag 1 'CORPORATION_NAME' ${corporation_name:-""} 166 tag 0 'CLIENT_ID' ${client_id:-""} 167 tag 1 'CLIENT_PRINT_NAME' ${client_print_name:-""} 168 tag_end 'CLIENT' 169 done < $datas 170 fi 171 tag_end 'ROOT' 172 rm $XMLSCRIPT/$CLIENT_LIST_QUERY_DATA 173 174 175 # add_wangxb_20150304 176 # Convert xml file encoding 177 # 这是将xml文件进行转码,命令是iconv 178 if [ -e "$XML_DIR/$MATCHING_RESULT_XML" ]; 179 then 180 echo "********** matching_result.xmlファイルコ〖ドを啪垂し、**********" 181 iconv -f euc-jp -t utf-8 $XML_DIR/$MATCHING_RESULT_XML -o $XML_DIR/$MATCHING_RESULT_XML.utf-8 182 mv $XML_DIR/$MATCHING_RESULT_XML.utf-8 $XML_DIR/$MATCHING_RESULT_XML 183 fi 184 if [ -e "$XML_DIR/$CLIENT_LIST_XML" ]; 185 then 186 echo "********** client_list.xmlフィルコ〖ドを啪垂し、**********" 187 iconv -f euc-jp -t utf-8 $XML_DIR/$CLIENT_LIST_XML -o $XML_DIR/$CLIENT_LIST_XML.utf-8 188 mv $XML_DIR/$CLIENT_LIST_XML.utf-8 $XML_DIR/$CLIENT_LIST_XML 189 fi 190 191 # add_wangxb_20150304 192 # Send the xml file to the destination server by ftp 193 #ftp_host="222.***.***.***" 194 #USER="***" 195 #PASS="***" 196 #ftp -i -n $ftp_host << EOF 197 #user $USER $PASS 198 #cd / 199 #lcd $XML_DIR/ 200 #put $MATCHING_RESULT_XML 201 #put $CLIENT_LIST_XML 202 #quit 203 #EOF 204 205 # test ftp 206 # 通过ftp将xml文件放到客户服务器上,ftp_host:客户服务器地址,user登录名,pass密码 207 ftp_host="***.***.***.***" 208 USER="***" 209 PASS="***" 210 dir="/upload" 211 ftp -i -n $ftp_host << EOF 212 user $USER $PASS 213 cd /upload/ 214 lcd $XML_DIR/ 215 put $MATCHING_RESULT_XML 216 put $CLIENT_LIST_XML 217 quit 218 EOF 219 220 221 # Save the program log file 222 YYMM=$(date +'%Y%m%d%H%M') 223 cp /tmp/create_xml.log /usr/p3s/batch/jaaa_match/tmp_xa_wangxb/logs/create_xml.log.$YYMM 224 225 # Send error log files into the Admin mailbox 226 info_to_mail_1="**@**.co.jp" 227 info_to_mail_2="***@**.co.jp" 228 # nkf 日文转码的一个命令 229 title=$(echo "test" | nkf -j) 230 nkf -j < /tmp/create_xml.log | mail -s $title $info_to_mail_1 $info_to_mail_2 231 232 233 #exit
关于nkf 日文转码:http://www.cnblogs.com/wxb0328/p/4333820.html
本来是用scp传送的,但是后面修改了,这里把自己为scp传送找到的一个,不用密码可立即登入的 ssh 用户
在鸟哥私房菜的服务器架设篇的第十一章中有介绍:http://vbird.dic.ksu.edu.tw/linux_server/0310telnetssh_2.php#ssh_nopasswd
下面是执行的两个sql文件
1 SET PAGESIZE 0 2 SET FEEDBACK OFF 3 SET VERIFY OFF 4 SET ECHO OFF 5 SET HEADING OFF 6 SET TIMI OFF 7 SET LINESIZE 1000 8 SET WRAP OFF 9 10 11 SELECT s.STOCKID|| '^*^' ||a.SERI_NO|| '^*^' ||a.MATCH_FLG|| '^*^' ||a.UNMATCH_RIYUU|| '^*^' ||to_char(a.UP_DATE,'YYYY-MM-DD@HH24: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; 12 13 exit
1 SET PAGESIZE 0 2 SET FEEDBACK OFF 3 SET VERIFY OFF 4 SET ECHO OFF 5 SET HEADING OFF 6 SET TIMI OFF 7 SET LINESIZE 1000 8 SET WRAP OFF 9 10 11 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; 12 13 exit
三、来看看效果
当然中间出现了许多bug,不过慢慢修改吗,兵来将挡,水来土掩,bug来了自己调么
就这样简单的整理一下,可能光这么写不够完整,但是,中间设计的知识也很多,不能展开了说,做个分享,大家有用到的时候也是个思路,具体的某些知识点可以用到了再去找资料了
题外话:
这几天打算辞职,想去外面,但是听了在外面找工作的同学说,外面要求的技术很多:“什么优化,缓存,环境搭建啊,高并发,读写分离,负载均衡等等” 。突然就没有了去外面的激情,而且毕竟才毕业半年,工资也不高,毕业前出去旅行也借了5K的钱都没有还,哎、、、本来想着去深圳,怎么也能找个6K+的工作,现在听听,觉得能力不够啊,这是这些能力也不是一天两天能掌握的,很郁闷,如果不出去,要等到什么时候,趁年轻不出去怕以后就没有机会!
哎、、、这个决定该怎么做,有点烦!如果哪位大牛能够看到小弟这篇博客,希望能提点建设性的意见,不胜感激!!涕泗横流!!!