经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 数据库/运维 » Linux/Shell » 查看文章
记一次bash脚本开发的经历
来源:cnblogs  作者:钟子敬07  时间:2019/4/9 9:22:23  对本文有异议

现状描述与需求描述

最近梳理系统功能的时候发现现在每个月处理完数据之后,需要给别的系统传送批接口文件,接口文件的内容是来自于Oracle数据表中的数据。我每次都需要手工执行一下存储过程,让数据从正式表中插入到接口表中,然后再借助plsql工具软件sqlplus的spool工具导出接口文件,然后把导出来的7个接口文件,打成zip压缩包,再通过前台系统实现上传(这一部分功能之前已经在前台系统实现部署上线了,详细可参见博文:https://www.cnblogs.com/zhongfengshan/p/9454259.html)。但是现在每个月都需要做这样的事情,很繁琐,而且每个月都需要耗费我的精力,程序猿的个性喜欢探索、创造、和解决问题,本着这样的态度,我开始了这件事的优化之旅。

方案分析

针对于此需求,大概有两种方案。

方案一:把这一系列的操作都写在Java后台的业务逻辑当中,然后通过前台系统每月传参数过去,实现调用。

方案二:可以用shell脚本实现存储过程的调用和数据接口文件的导出和压缩。

由于系统是一个老系统,各种技术框架个分层并没有那么明显,而且有7个文件之多,用Java写起来无论是业务逻辑还是代码量都是及其多,而且不方便测试和调试。相比之下,用shell脚本写,逻辑变得清晰明了,导出的接口文件写在sql文件中,用sqlplus去执行它便可。因此我选用了方案二。

开始实现

第一步:细化业务逻辑,第一步就是需要去调用一个存储过程,存储过程的主要作用是把正式表中当月的数据插入到接口表中。这一步很简单,代码如下

  1. sqlplus zh/dbpassword@zh10g << sql
  2. declare
  3. imonth varchar2(6);
  4. strrtn varchar2(8);
  5. countnum NUMBER;
  6. begin
  7. select to_char(add_months(sysdate,-1),'YYYYMM') into imonth from dual;
  8. SELECT count(*) INTO countnum FROM t_report_if_carrier
  9. WHERE bill_cycle=imonth;
  10. IF (countnum=0) THEN
  11. Dbms_Output.put_line(imonth+':'+countnum);
  12. PR_REPORT_IF(imonth,strrtn);
  13. END IF;
  14. end;
  15. /
  16. sql

计算出当月的上一个月是多少,然后判断表中有没有该月的数据,如果没有,则认为没有执行该存储过程,需要执行存储过程

第二步:需要对导出文件的目录做一下清理,如果上次导出过了,则删除再重新到导出,代码如下:

  1. cd /workforzhongfs/jffile/
  2. rm -rf $report_month
  3. mkdir $report_month
  4. cd $report_month

第三步:把需要执行导出的语句放到一个spoll_file.sql文件中,然后通过sqlplus调用$report_month 代表着需要传给脚本的当前月的上一个月的参数,如现在是2019年04月,则参数为201903

  1. sqlplus zh/dbpassword@zh10g @/workforzhongfs/spoll_file.sql $report_month

spoll_file.sql的内容如下,其中&1代表$report_month传过来的月份参数。

  1. SET NEWPAGE 0
  2. SET SPACE 0
  3. SET LINESIZE 2500
  4. SET PAGESIZE 0
  5. SET ECHO OFF
  6. SET FEEDBACK OFF
  7. SET VERIFY OFF
  8. SET HEADING OFF
  9. SET MARKUP HTML OFF SPOOL OFF
  10. SET COLSEP ' '
  11. SET TRIMSPOOL ON
  12. SET TERMOUT OFF
  13. COL report_name FORMAT a35
  14. COL report_name NEW_VALUE rpt_name
  15. select 'CMBFYDWAL06002A'||&1||'0000000.000' as report_name from dual;
  16. SPOOL &rpt_name
  17. select bank_warrant_no || CHR(9)|| rec_pay_date || CHR(9)|| bank_name || CHR(9)||
  18. record_flag || CHR(9)|| carrier_name || CHR(9)|| carrier_id || CHR(9)||
  19. descript || CHR(9)|| amount_bill || CHR(9)|| exchange_name2 || CHR(9)||
  20. rate_bill || CHR(9)|| amount || CHR(9)|| exchange_name || CHR(9)|| rate || CHR(9)||
  21. amount_rmb || CHR(9)|| bank_fee || CHR(9)|| remark || CHR(9)|| bill_cycle || CHR(9)||
  22. erp_def_code as data
  23. from t_report_if_recpay a
  24. WHERE 1 = 1
  25. and bill_cycle=&1 order by erp_def_code asc;
  26. SPOOL OFF
  27. select 'CMBFYDWAL06005A'||&1||'0000000.000' as report_name from dual;
  28. SPOOL &rpt_name
  29. select ADVANCE_NO || CHR(9)|| carrier_name || CHR(9)|| WARRANT_NO || CHR(9)||
  30. REC_DATE || CHR(9)|| EXCHANGE_NAME || CHR(9)|| AMOUNT || CHR(9)||
  31. AMOUNT_RMB || CHR(9)|| BALANCE || CHR(9)|| BALANCE_RMB as data
  32. from t_report_if_advance
  33. WHERE 1 = 1
  34. and bill_cycle=&1 order by erp_def_code asc;
  35. SPOOL OFF
  36. select 'CMBFYDWAL06006A'||&1||'0000000.000' as report_name from dual;
  37. SPOOL &rpt_name
  38. select BAIL_NO || CHR(9)|| carrier_name || CHR(9)|| warrant_no || CHR(9)||
  39. REC_DATE || CHR(9)|| EXCHANGE_NAME || CHR(9)|| AMOUNT || CHR(9)||
  40. AMOUNT_RMB || CHR(9)|| BALANCE || CHR(9)|| BALANCE_RMB || CHR(9)||
  41. bill_cycle || CHR(9)|| erp_def_code as data
  42. from t_report_if_bail
  43. WHERE 1 = 1
  44. and bill_cycle=&1 order by erp_def_code asc;
  45. SPOOL OFF
  46. select 'CMBFYDWAL06007A'||&1||'0000000.000' as report_name from dual;
  47. SPOOL &rpt_name
  48. select report_month || CHR(9)|| center || CHR(9)|| period || CHR(9)|| types || CHR(9)||
  49. property || CHR(9)|| carrier_name || CHR(9)|| customer_number || CHR(9)||
  50. currency || CHR(9)|| duration || CHR(9)|| amount || CHR(9)|| basiccurrency || CHR(9)||
  51. reference_no || CHR(9)|| bill_cycle || CHR(9)|| erp_def_code as data
  52. from t_report_if_rp
  53. WHERE 1 = 1
  54. and bill_cycle=&1 order by erp_def_code asc;
  55. SPOOL OFF
  56. select 'CMBFYDWAL01001A'||&1||'0000000.000' as report_name from dual;
  57. SPOOL &rpt_name
  58. select DATA_TYPE|| CHR(9) ||CHINESENAME|| CHR(9) ||
  59. CARRIER_NAME|| CHR(9) ||CARRIER_ID|| CHR(9) ||ACCOUNT_CODE|| CHR(9) ||
  60. ACCOUNT_NAME|| CHR(9) ||CONTACT_PERSON|| CHR(9) ||
  61. TELEPHONE_NO|| CHR(9) ||EMAIL_ADDRESS|| CHR(9) ||
  62. BENEFICIARY_NAME|| CHR(9) ||ACCO_LINKMAN_PHONE|| CHR(9) ||
  63. ACCO_LINKMAN_EMAIL|| CHR(9) ||BUSI_MANA_NAME|| CHR(9) ||
  64. ACCO_MANA_NAME as data
  65. from t_report_if_carrier
  66. WHERE 1 = 1
  67. and bill_cycle=&1 order by erp_def_code asc;
  68. SPOOL OFF
  69. select 'CMBFYDWAL06004A'||&1||'0000000.000' as report_name from dual;
  70. SPOOL &rpt_name
  71. select carrier_name || CHR(9)|| destroybill_no || CHR(9)|| settle_flag || CHR(9)||
  72. service_name || CHR(9)|| load_date || CHR(9)|| jfdate || CHR(9)|| settdate || CHR(9)||
  73. exchange_name || CHR(9)|| settle_amount || CHR(9)|| settle_amount_new || CHR(9)||
  74. bill_cycle || CHR(9)|| erp_def_code as data
  75. From t_report_if_destroys
  76. WHERE 1 = 1
  77. and bill_cycle=&1 order by erp_def_code asc;
  78. SPOOL OFF
  79. select 'CMBFYDWAL06001A'||&1||'0000000.000' as report_name from dual;
  80. SPOOL &rpt_name
  81. select carrier_name || CHR(9)|| carrier_no || CHR(9)|| center_name || CHR(9)||
  82. destroybill_no || CHR(9)|| rec_pay || CHR(9)|| buy_property || CHR(9)||
  83. service_no || CHR(9)|| map_name || CHR(9)|| load_date || CHR(9)|| jfdate || CHR(9)||
  84. settdate || CHR(9)|| end_date || CHR(9)|| exchange_name || CHR(9)||
  85. settle_amount || CHR(9)|| settle_amount_rmb || CHR(9)|| current_amount || CHR(9)||
  86. amount_30 || CHR(9)|| amount_90 || CHR(9)|| amount_180 || CHR(9)||
  87. amount_360 || CHR(9)|| AMOUNT_720 || CHR(9)|| AMOUNT_1080 || CHR(9)||
  88. AMOUNT_1440 || CHR(9)|| AMOUNT_1800 as data
  89. From t_report_if_datadetail
  90. WHERE 1 = 1
  91. and bill_cycle=&1 order by erp_def_code asc;
  92. SPOOL OFF
  93. QUIT

遇到的问题

问题一:原本以为这样问题就可以得到解决了,万万没想到,spool导出的文件换行符出现了问题,Windows下的换行符是“\r\n”,而Linux的则是“\n”,这样导致看起来的文件内容是一样的实则是不一样的,用MD5校验之后发现二者不一致。

问题二:导出的CMBFYDWAL01001A2019030000000.000文件每一行的行末有大量的空格,而在windows下用plsql软件导出来的该接口文件没有这个问题。

问题解决

在网上变换各种搜索关键词和不断地试验测试,最终问题都得到解决

问题二的解决,用sed把行末的空格替换成空,

  1. sed 's/[[:space:]][[:space:]]*$//g' $file>$file-sed

问题一的解决,这样子就可以把换行符从Linux的替换为Windows下的换行符。

  1. awk '{ print $0"\r" }'<$file-sed > $file-fs

写了一个循环,当前目录下的所有文件都可以得到替换。

  1. for file in CMBFY*
  2. do
  3. sed 's/[[:space:]][[:space:]]*$//g' $file>$file-sed
  4. awk '{ print $0"\r" }'<$file-sed > $file-fs
  5. echo $file >> $report_month.log
  6. done

还遇到什么问题

解决了上述的问题,那么还遇到什么问题呢?

我把这个脚本 加到crontab中执行的时候,发现脚本开始需要制定月份参数,这样子不又回到了原点么?因此,我必须要解决这个问题。我在网上搜索,大多数人都告诉我用“date -d”可以计算上月的月份,但是我的程序是部署在AIX中的,AIX没有这些奇奇怪怪的选项,采取了个折中的办法,如下代码

  1. month=`date +%m |sed 's/$/b12a01a02a03a04a05a06a07a08a09a10a11a12/;
  2. s/^\(..\)b.*\(..\)a\1.*/\2/'`
  3. year=`date +%Y`
  4. report_month="$year$month"

这样便能计算出上一个月(虽然我也不太知道原理),以下为测试截图

最后加到crontab中便可以自动执行了

最后

万事大吉,愿世界没有bug。

原文链接:http://www.cnblogs.com/zhongfengshan/p/10671691.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号