linux 开发自己bash,记一次bash脚本开发的经历

现状描述与需求描述

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

方案分析

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

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

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

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

开始实现

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

sqlplus zh/dbpassword@zh10g << sql

declare

imonth varchar2(6);

strrtn varchar2(8);

countnum number;

begin

select to_char(add_months(sysdate,-1),'yyyymm') into imonth from dual;

select count(*) into countnum from t_report_if_carrier

where bill_cycle=imonth;

if (countnum=0) then

dbms_output.put_line(imonth+':'+countnum);

pr_report_if(imonth,strrtn);

end if;

end;

/

sql

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

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

cd /workforzhongfs/jffile/

rm -rf $report_month

mkdir $report_month

cd $report_month

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

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

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

set newpage 0

set space 0

set linesize 2500

set pagesize 0

set echo off

set feedback off

set verify off

set heading off

set markup html off spool off

set colsep ' '

set trimspool on

set termout off

col report_name format a35

col report_name new_value rpt_name

select 'cmbfydwal06002a'||&1||'0000000.000' as report_name from dual;

spool &rpt_name

select bank_warrant_no || chr(9)|| rec_pay_date || chr(9)|| bank_name || chr(9)||

record_flag || chr(9)|| carrier_name || chr(9)|| carrier_id || chr(9)||

descript || chr(9)|| amount_bill || chr(9)|| exchange_name2 || chr(9)||

rate_bill || chr(9)|| amount || chr(9)|| exchange_name || chr(9)|| rate || chr(9)||

amount_rmb || chr(9)|| bank_fee || chr(9)|| remark || chr(9)|| bill_cycle || chr(9)||

erp_def_code as data

from t_report_if_recpay a

where 1 = 1

and bill_cycle=&1 order by erp_def_code asc;

spool off

select 'cmbfydwal06005a'||&1||'0000000.000' as report_name from dual;

spool &rpt_name

select advance_no || chr(9)|| carrier_name || chr(9)|| warrant_no || chr(9)||

rec_date || chr(9)|| exchange_name || chr(9)|| amount || chr(9)||

amount_rmb || chr(9)|| balance || chr(9)|| balance_rmb as data

from t_report_if_advance

where 1 = 1

and bill_cycle=&1 order by erp_def_code asc;

spool off

select 'cmbfydwal06006a'||&1||'0000000.000' as report_name from dual;

spool &rpt_name

select bail_no || chr(9)|| carrier_name || chr(9)|| warrant_no || chr(9)||

rec_date || chr(9)|| exchange_name || chr(9)|| amount || chr(9)||

amount_rmb || chr(9)|| balance || chr(9)|| balance_rmb || chr(9)||

bill_cycle || chr(9)|| erp_def_code as data

from t_report_if_bail

where 1 = 1

and bill_cycle=&1 order by erp_def_code asc;

spool off

select 'cmbfydwal06007a'||&1||'0000000.000' as report_name from dual;

spool &rpt_name

select report_month || chr(9)|| center || chr(9)|| period || chr(9)|| types || chr(9)||

property || chr(9)|| carrier_name || chr(9)|| customer_number || chr(9)||

currency || chr(9)|| duration || chr(9)|| amount || chr(9)|| basiccurrency || chr(9)||

reference_no || chr(9)|| bill_cycle || chr(9)|| erp_def_code as data

from t_report_if_rp

where 1 = 1

and bill_cycle=&1 order by erp_def_code asc;

spool off

select 'cmbfydwal01001a'||&1||'0000000.000' as report_name from dual;

spool &rpt_name

select data_type|| chr(9) ||chinesename|| chr(9) ||

carrier_name|| chr(9) ||carrier_id|| chr(9) ||account_code|| chr(9) ||

account_name|| chr(9) ||contact_person|| chr(9) ||

telephone_no|| chr(9) ||email_address|| chr(9) ||

beneficiary_name|| chr(9) ||acco_linkman_phone|| chr(9) ||

acco_linkman_email|| chr(9) ||busi_mana_name|| chr(9) ||

acco_mana_name as data

from t_report_if_carrier

where 1 = 1

and bill_cycle=&1 order by erp_def_code asc;

spool off

select 'cmbfydwal06004a'||&1||'0000000.000' as report_name from dual;

spool &rpt_name

select carrier_name || chr(9)|| destroybill_no || chr(9)|| settle_flag || chr(9)||

service_name || chr(9)|| load_date || chr(9)|| jfdate || chr(9)|| settdate || chr(9)||

exchange_name || chr(9)|| settle_amount || chr(9)|| settle_amount_new || chr(9)||

bill_cycle || chr(9)|| erp_def_code as data

from t_report_if_destroys

where 1 = 1

and bill_cycle=&1 order by erp_def_code asc;

spool off

select 'cmbfydwal06001a'||&1||'0000000.000' as report_name from dual;

spool &rpt_name

select carrier_name || chr(9)|| carrier_no || chr(9)|| center_name || chr(9)||

destroybill_no || chr(9)|| rec_pay || chr(9)|| buy_property || chr(9)||

service_no || chr(9)|| map_name || chr(9)|| load_date || chr(9)|| jfdate || chr(9)||

settdate || chr(9)|| end_date || chr(9)|| exchange_name || chr(9)||

settle_amount || chr(9)|| settle_amount_rmb || chr(9)|| current_amount || chr(9)||

amount_30 || chr(9)|| amount_90 || chr(9)|| amount_180 || chr(9)||

amount_360 || chr(9)|| amount_720 || chr(9)|| amount_1080 || chr(9)||

amount_1440 || chr(9)|| amount_1800 as data

from t_report_if_datadetail

where 1 = 1

and bill_cycle=&1 order by erp_def_code asc;

spool off

quit

遇到的问题

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

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

问题解决

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

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

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

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

awk '{ print $0"\r" }' $file-fs

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

for file in cmbfy*

do

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

awk '{ print $0"\r" }' $file-fs

echo $file >> $report_month.log

done

还遇到什么问题

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

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

month=`date +%m |sed 's/$/b12a01a02a03a04a05a06a07a08a09a10a11a12/;

s/^\(..\)b.*\(..\)a\1.*/\2/'`

year=`date +%y`

report_month="$year$month"

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

9e7c4612ceb6324744dc5e122af96738.png

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

最后

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值