2009年12月12日 星期六

unix shell script來處理時間

#!/bin/bash

now_sec=$(expr `date +%H` \* 60 \* 60 + `date +%M` \* 60 + `date +%S`) 
echo $now_sec 

time_stamp=$(date +"%H %M %S"); 
now_sec=$(expr $(echo $time_stamp | awk '{print $1}') \* 3600) 
now_sec=$(expr $now_sec + $(echo $time_stamp | awk '{print $2}') \* 60) 
now_sec=$(expr $now_sec + $(echo $time_stamp | awk '{print $3}') ) 
echo $now_sec 

#the MSYS doesn't have bc command 
#now_sec=$(echo "$(date +'%H * 3600 + %M * 60 + %S')" | bc ) 
#echo $now_sec 

now_sec=$(($(date +' 10#%H * 3600 + 10#%M * 60 + 10#%S'))) 
echo $now_sec 


這裡列出如何用linux shell script,算出,現在是一天開始的第幾秒,有四個做法,除了第一個做法有疑慮,其它應該都沒問題,不過這樣的演變是有些心路歷程,所以紀錄一下... 

第一個方法,可以看到使用date指令三次,有一種可能錯誤的狀況,就是當時間為1:59:59,第一次date +%H抓到 1, 第二次好死不死,時間變成2:00:00,所以date +%M變成 00,然後date +%S,也許抓到01或02,所以結果可想而知和事實差了1個小時...所以不太好 

第二個方法,就先把時間的字串紀錄下來,然後再透過awk來各別處理...雖然沒問題,但是有點冗長 

第三個方法是我發現date輸出的格式,可以有些調整,所以加了一些輔助的字元,然後轉向給bc這指令算出... 
其實在考慮bc指令前,我有想過expr指令,不過我發現有些困難... 
首先expr指令的算式,各個operator and operand都需要空白隔開...這應該對shell script熟的人,覺得是常識,我還算菜鳥...CC 
再來這個*的運算符號,必須要這樣\*,前面加個escape符號隔開,否則會告訴你說syntax error... 
然後我想出了這個$(expr `date +'%H \* 360 + %M \* 60 + %S'`) 或者這樣$(expr $(date +'%H \* 360 + %M \* 60 + %S')),結果都是syntax error,我搞了半天,還是參不出道理...結果是放棄,換了bc這指令 

其實搞這些,主要是做些實驗,每隔固定時間,做一些存取動作,然後將結果和時間標記存成.csv的格式,而我是在vmware的linux環境下做的,當我開心的寫好script,開始給它一天時間,去收集資料後,才發現到vmware有個bug,就是vmware下的guest os,時間會不準,所以我那個收集資料的script,就破功了...嗚嗚...我google了一下,好像有解決方法,不過我沒去試,因為我想到,如果某個條件後,就可以停止收集資料,那電腦就會一直開著,直到我發現,然後才有機會關掉電腦,這樣有點不環保,浪費電...而在vmware的linux環境下,雖然有指令可以關機,不過關的是vmware的linux,而不是把電腦關機,所以我選擇在windows上執行這個script,當然,windows認不得這個linux shell script,而我也不太想學windows的shell script,所以弄了個MSYS的東東,用它來解譯我之前寫的linux shell script,同時找出在windows下如何透過cmd下命令,來關機,然後加進我寫的shell scirpt,這樣就蠻順心如意了...哈哈 

可是問題又來了,bc這指令沒有也,雖然我可以找到bc的source code透過MinGW編譯出來,或著用cygwin這個比較完善的unix環境(我想它應該有bc),不過我沒選擇前兩條路,我又在shell script這裡下工夫,我又發現,如果這樣寫$((...)),裡面的...會當作算式處理,然後我一開始時是這樣寫的$(($(date +' %H * 3600 + %M * 60 + %S'))),結果跑一段時間就會停掉,檢查一下,發現是因為如果像是01. 02. 012, 其實是被當八進位處理,所以實際十進位是1. 2. 10, 而如果出現08. 09,就會沒法處理,因為八進位只允許0~7,結果再google一下,發現到只要前面加個10#就會告訴shell interpreter,這個數值就會被用十進位來解釋 

看來我希望的目的是達到了...還有一個"date +%s"(小寫),它是給出從1970/1/1到現在的時間秒數,也是可以考慮的時間處理方法 

最後附上windows的關機指令 
關機 shutdown -s 
重開機 shutdown -r 
shutdont -?,查一下,說的很清楚

補充(20091228):
把bash的wildcard(*)關掉,也可以(注意空白)
#!/bin/bash
set -f
now_sec=$(expr $(date +'%H * 360 + %M * 60 + %S'))
echo $now_sec

相關連結: