記一次bash腳本開發的經歷

来源:https://www.cnblogs.com/zhongfengshan/archive/2019/04/08/10671691.html
-Advertisement-
Play Games

現狀描述與需求描述 最近梳理系統功能的時候發現現在每個月處理完數據之後,需要給別的系統傳送批介面文件,介面文件的內容是來自於Oracle數據表中的數據。我每次都需要手工執行一下存儲過程,讓數據從正式表中插入到介面表中,然後再藉助plsql工具軟體sqlplus的spool工具導出介面文件,然後把導出 ...


現狀描述與需求描述

最近梳理系統功能的時候發現現在每個月處理完數據之後,需要給別的系統傳送批介面文件,介面文件的內容是來自於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-sed > $file-fs

寫了一個迴圈,當前目錄下的所有文件都可以得到替換。

for file in CMBFY*
    do
    sed 's/[[:space:]][[:space:]]*$//g' $file>$file-sed
    awk '{ print $0"\r" }'<$file-sed > $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"

這樣便能計算出上一個月(雖然我也不太知道原理),以下為測試截圖

最後加到crontab中便可以自動執行了

最後

萬事大吉,願世界沒有bug。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Windows 使用 L2TP 協議連接VPN服務 首先, 點擊"添加 VPN 連接" 其次, 選擇 L2TP 協議 此時若嘗試連接發現會失敗, 打開網路共用中心, 會發現多了一個 VPN 的連接, 右鍵屬性 勾選相應選項, 再嘗試連接即可成功. ...
  • 先說BUG,最近要做項目需要樹莓派和陀螺儀,資金充足的話肯定是買一個硬體卡爾曼濾波的感測器類似JY901模塊,資金不足的就買MPU6050。 網上關於MPU6050在樹莓派上的代碼還能用,關於JY901的代碼真的是千奇百怪,而且複製現象特別嚴重,有很多系統本身有問題,導致很多像我一樣的新手在上面浪費 ...
  • 1. 主機規劃 Targeting Minions文檔 另請參見:自動化運維神器之saltstack (三)節點組及複合匹配器 註意事項 修改了master或者minion的配置文件,那麼必須重啟對應的服務。 2. 目標指定方式 Letter Match Type Example Alt Delim ...
  • 本文主要介紹一下阿裡雲CentOS7下如何對MySql 8.0資料庫進行自動備份,並使用.NET Core 將備份文件上傳至七牛雲存儲上,並對整個過程所踩的坑加以記錄. 環境、工具、準備工作 伺服器:阿裡雲64位CentOS 7.4.1708版本;並安裝MySql 8.0 資料庫(如何安裝點擊) 客 ...
  • Windows 評估和部署工具包 (Windows ADK) 具有自定義大規模部署的 Windows 映像以及測試系統、添加的組件和在該系統上運行的應用程式的質量和性能所需的工具。 Windows ADK 包括:用於評估系統或組件的質量和性能的 Windows 評估工具包和 Windows Perf ...
  • 想學會如何在STM8上使用ADC這個功能,我們先得瞭解單片機中ADC究竟是什麼。 ADC是模擬信號轉成數值信號,單片機只能識別TTL電平,其實就是 1 或者 0 ,但是如果我們給它一個3.3V電壓,單片機就無法識別,,若想使用單片機讀取出來得時候,它必須將模擬量變成數字量。 瞭解完後,我們就開始講解 ...
  • [TOC]     1. Linux啟動過程 Linux的啟動過程是在執行多級初始化過程中啟動一個Linux的安裝,它在許多方面類似於BSD和其他Unix風格的引導過程,從中衍生出來。   引導Linux安裝設計多個階段和軟體組成,包括固件初始化,引導載入程式的執行,L ...
  • 必要瞭解函數的功能和使用場景: fflush, setbuf, setvbuf 瞭解的操作: setbuf(stdout,NULL); // 關閉輸出緩衝區; 保持更新,轉載請註明出處。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...