馬宏陽(yáng),張龍平
(1.中國(guó)測(cè)繪科學(xué)研究院,北京 100830;2.山東科技大學(xué),山東 青島 266510)
Linux是一套可免費(fèi)使用和自由傳播的類UNIX操作系統(tǒng),經(jīng)過(guò)近20年來(lái)的發(fā)展,Linux成為了一個(gè)支持多用戶、多進(jìn)程、多線程,實(shí)時(shí)性較好、功能強(qiáng)大而穩(wěn)定的操作系統(tǒng),它也是目前支持硬件平臺(tái)最多的操作系統(tǒng)[1-3]。除了桌面領(lǐng)域,Linux在其他領(lǐng)域都取得了巨大的進(jìn)步和成功。其開放、安全、穩(wěn)定的特性得到越來(lái)越多用戶的認(rèn)可,許多導(dǎo)航定位領(lǐng)域廣泛應(yīng)用的軟件都是基于Linux開發(fā)[4],如GAMIT/GlobK、GIPS、Bernese、PANDA等。許多IGS分析中心也將Linux作為平臺(tái)操作系統(tǒng)。Linux自誕生以來(lái)發(fā)布了許多不同的版本,常見的有Slackware、RedHat、Debian、Fedora、S.u.s.E.等。本文的實(shí)驗(yàn)環(huán)境選擇了S.u.s.E. 11,它是2008年發(fā)布的S.u.s.E.版本,是一個(gè)開放的、創(chuàng)新的、具有前瞻性的免費(fèi)Linux系統(tǒng)。
Shell是一種具備特殊功能的程序,它提供了用戶與內(nèi)核進(jìn)行交互操作的一種接口,它接受用戶輸入的命令,并把它送入內(nèi)核去執(zhí)行[5-6]。內(nèi)核是Linux系統(tǒng)的心臟,當(dāng)用戶登錄Linux系統(tǒng)時(shí),Shell就會(huì)被調(diào)入內(nèi)存執(zhí)行。Shell獨(dú)立于內(nèi)核,它是連接內(nèi)核和應(yīng)用程序的橋梁,并由輸入設(shè)備讀取命令,再將其轉(zhuǎn)為計(jì)算機(jī)可以理解的機(jī)械碼,Linux才能執(zhí)行該命令。本文根據(jù)實(shí)際工作經(jīng)驗(yàn),詳細(xì)介紹了C Shell語(yǔ)言在Linux系統(tǒng)下輔助衛(wèi)星定軌軟件起到的作用。
數(shù)據(jù)解算的第一步是下載所需的數(shù)據(jù),如觀測(cè)文件、廣播星歷和頻間偏差等文件,對(duì)于衛(wèi)星定軌而言,需要下載幾十甚至上百個(gè)觀測(cè)站的數(shù)據(jù),如果手動(dòng)下載會(huì)非常繁瑣,本節(jié)介紹兩個(gè)常用的數(shù)據(jù)下載命令。
以下載MGEX觀測(cè)站的多模觀測(cè)文件的小時(shí)文件為例,其命令為
set pth=/cddis.gsfc.nasa.gov/pub/gnss/data
set site-list=site-list-mgex
set chour=(a b c d e f g h i j k l m n o p q r s t u v w x)
set ihour=$hour+1
foreach s (`cat $site-list`)
wget ftp://$pth/hourly/$yyyy/$doy/$hour/$s$doy$chour[$ihour].$yy"o.Z"
end
其中,$pth為MGEX數(shù)據(jù)下載路徑;$yyyy、$doy、$hour分別為年、年積日、小時(shí),均可以作為變量輸入;$site-list為需要下載的站列表文件;$yy 為兩位數(shù)的年;foreach為循環(huán)站列表文件,并將站名賦給$s;$s$doy$chour[$ihour].$yy"o.Z"即為需要下載的某個(gè)測(cè)站小時(shí)觀測(cè)文件名稱,全部使用變量表示,因此利用該腳本,可以下載任意時(shí)段的指定站列表小時(shí)數(shù)據(jù)。
該網(wǎng)站的數(shù)據(jù)可以免費(fèi)下載,若下載數(shù)據(jù)的ftp地址設(shè)置了用戶名和密碼,可以將命令改寫為
wget-ftp-user=user_name-ftp-password
=secret
值得注意的是,wget會(huì)不斷的嘗試下載沒(méi)有下載成功的數(shù)據(jù),因此有必要介紹兩個(gè)常用的參數(shù),-t為設(shè)置下載嘗試次數(shù),-w為設(shè)置下載最大時(shí)長(zhǎng),均可以避免在一個(gè)站上消耗大量時(shí)間。
一般IGS站的小時(shí)觀測(cè)文件延遲半小時(shí)之內(nèi)上傳,而MGEX站會(huì)延遲更長(zhǎng)時(shí)間,因此有可能出現(xiàn)在下載時(shí)刻數(shù)據(jù)還沒(méi)有上傳的情況,因此最好是下載完成一個(gè)小時(shí)的數(shù)據(jù)后,再補(bǔ)下前一個(gè)小時(shí)的數(shù)據(jù),命令為
while (0 < 1)
@ hour=$hour-1
if($hour < 0)then
@doy=$doy-1
if($doy==0)then
@yyyy=$yyyy-1
@doy=`dpy $yyyy`
endif
@ hour=23
endif
set hour=`echo $hour | awk '{printf("%2.2d",$1)}'`
set doy=`echo $doy | awk '{printf("%3.3d",$1)}'`
……
end
該腳本實(shí)現(xiàn)將時(shí)間調(diào)至前一個(gè)小時(shí),while (0 < 1)給出一個(gè)死循環(huán),只要不結(jié)束該腳本,它就會(huì)一直循環(huán)補(bǔ)充下載前一個(gè)小時(shí)的觀測(cè)文件;若是出現(xiàn)跨天的情況,則年積日減1,$hour變?yōu)?3,若是出現(xiàn)跨年的情況,則年減1,年積日為該年的最后一天,@ doy=`dpy $yyyy`為調(diào)用“dyp”命令,計(jì)算該年有多少天;awk '{printf("%2.2d",$1)}為將$hour寫成兩位數(shù)的小時(shí),同樣,$doy也寫成三位數(shù)的年積日,這是為了和下載目錄向?qū)?yīng)。
既然給出了while (0 < 1)的死循環(huán),肯定有一個(gè)時(shí)刻要將該腳本關(guān)閉??梢允紫仁褂谩皃s-ef”查看該腳本運(yùn)行的ID,再使用“kill-9 %ID”強(qiáng)制關(guān)閉腳本的進(jìn)程。使用這種方法每次都需要人工查看腳本ID,不適合自動(dòng)化運(yùn)行,因此可以使用如下結(jié)束進(jìn)程的腳本:
set name="get_hourly"
set id=`ps-ef | grep "$name" | grep-v"$0" | grep-v"grep" | awk’{print $2}’
kill-9 $id
這樣,僅給出需要結(jié)束的進(jìn)程名稱(get_hourly),腳本就可以自動(dòng)獲取其進(jìn)程ID,結(jié)束該進(jìn)程。
該命令與wget命令的區(qū)別是,wget每下載一個(gè)數(shù)據(jù)都要登入和登出一次,而mget登入后,會(huì)將所需文件全部下載完畢才登出,從理論上講,mget會(huì)比wget的效率更高。由于使用mget命令需要登錄對(duì)方服務(wù)器,因此必須設(shè)置用戶名和密碼,其命令為
if(!-d./$yyyy)then
mkdir $yyyy
cd./$yyyy/
mkdir $doy
cd $pth-pwd
endif
set file-name=""
foreach s (`cat $site-list`)
set file-name=($file-name $s$doy$chour[$ihour].$yy"o.Z")
end
set HOST="cddis.gsfc.nasa.gov"
set USER="anonymous"
set PASS='^M'
ftp -inv $HOST ?EOF
user $USER $PASS
cd/gnss/data/campaign/mgex/hourly/rinex3/$yyyy/$doy/$hour/
mget $file-name
bye
EOF
該腳本首先判斷有沒(méi)有存放數(shù)據(jù)的文件夾,若沒(méi)有,建立年和年積日的文件夾;由于登入對(duì)方服務(wù)器有許多操作限制,因此需要事先定義好需要下載的文件名$file-name;該網(wǎng)站的數(shù)據(jù)可以免費(fèi)下載,可以使用"anonymous"匿名登錄,登錄密碼'^M'相當(dāng)于“回車”的作用;語(yǔ)句“ftp-inv”相當(dāng)于登入對(duì)方服務(wù)器,許多Cshell命令在該狀態(tài)下無(wú)法使用。
以下載小時(shí)觀測(cè)文件為例,下載小時(shí)廣播星歷文件也類似。
為保證超快速軌道解算的實(shí)時(shí)性,國(guó)際IGS分析中心一般使用小時(shí)文件合并成天文件進(jìn)行解算。另外,最終產(chǎn)品可能需要一個(gè)周或更長(zhǎng)的時(shí)間進(jìn)行解算,這需要將多天的文件合并成一個(gè)文件。這一節(jié)介紹小時(shí)文件合并和天文件合并。
合并文件之前,需要將準(zhǔn)備合并的小時(shí)文件放到一個(gè)文件夾中,然后使用命令:
set f-day=$s$doy"0."$yy"o"
foreach s ('ls $s$doy*.$yy"o"')
if(-e $f-day)then
cat $s | awk ’/BEIN/{i=0}/END OF HEADER/{i=NR} {if(NR> i && i!=0)print $0}’? $f_day
else
cat $s? $f-day
endif
end
其中,$f-day為該站合并后天文件文件名;$s$doy*.$yy"o"為該站的小時(shí)文件名,“*”為通配符,代表小時(shí)文件的標(biāo)識(shí)a~z;“if(-e $f-day)”為判斷是否已經(jīng)存在合成的天文件,若不存在,則將頭文件和數(shù)據(jù)記錄一起寫入天文件中,若存在,則將標(biāo)識(shí)符“END OF HEADER”之后的數(shù)據(jù)記錄寫入天文件中,由于每個(gè)小時(shí)文件都有頭文件,使用這種判斷可以避免天文件中有多個(gè)頭文件。
天文件合并的方法與小時(shí)文件合并類似,僅需要將$s$doy*.$yy"o"改為$s*"0."$yy"o"即可。
值得注意的是,MGEX使用3.xx格式的多模觀測(cè)數(shù)據(jù),其數(shù)據(jù)格式與2.xx有較大區(qū)別:其一是在頭文件中加入了更多的觀測(cè)類型,如圖1所示;其二是數(shù)據(jù)記錄方式也隨頭文件做了修改。
圖1 RINEX3.02格式文件(部分)
在該頭文件中可以看出,該站觀測(cè)到了G(GPS)、S(SBSA)、R(GLONASS)、E(GALILEO)、C(BDS),由于每個(gè)小時(shí)觀測(cè)到的衛(wèi)星系統(tǒng)不盡相同,因此在合并成天文件后會(huì)出現(xiàn)頭文件觀測(cè)類型和數(shù)據(jù)記錄不相符的情況,這就為后續(xù)使用該觀測(cè)文件埋下了隱患。為了避免這種情況發(fā)生,使頭文件和數(shù)據(jù)記錄統(tǒng)一,應(yīng)該首先遍歷需要合并的小時(shí)觀測(cè)文件,找到頭文件觀測(cè)類型最多的小時(shí)文件作為天文件的頭文件。因此,上述合并文件腳本可以進(jìn)一步優(yōu)化為
foreach s (`ls $s$doy*.$yy"o"`)
set bb=` grep -n "SYS/#/OBS TYPES" "$s" | head-1 | cut -d ":"-f 1 '
set cc=` grep -n "SYS/#/OBS TYPES" "$s" | tail-1 | cut -d ":"-f 1'
@ aa=$cc-$bb
set aa1=0
if($aa> $aa1)then
at $s | awk '/BEIN/{i=0}/END OF HEADER/{i=NR} {if(NR < i && i!=0)print $0}'? $f_day
endif
@ aa1=$aa
end
該腳本的目的是以頭文件觀測(cè)類型最多的小時(shí)文件作為天文件的頭文件,其中$bb和$cc分別為查找"SYS/#/OBS TYPES"標(biāo)識(shí)符的起始行和結(jié)束行,然后做差,取其差后$aa最大的小時(shí)文件的頭文件作為天文件的頭文件。
一般一個(gè)服務(wù)器組都是由多臺(tái)服務(wù)器構(gòu)成。它們之間通過(guò)內(nèi)網(wǎng)相互聯(lián)系,如圖1所示。內(nèi)網(wǎng)的跨服務(wù)器數(shù)據(jù)傳輸可以用以下命令:
scp root @99.99.99.1: root/data/obs/$yy
yy/$doy/*.*o./
scp -r root @99.99.99.1: root/data/nav/$yyyy/$doy./
第一個(gè)scp是從內(nèi)網(wǎng)地址99.99.99.1的服務(wù)器中指定目錄下的觀測(cè)文件拷貝到運(yùn)行該命令的服務(wù)器的當(dāng)前路徑下;第二個(gè)添加了控制“-r”,是拷貝整個(gè)文件夾。
由于命令跨服務(wù)器拷貝數(shù)據(jù),因此需要手動(dòng)輸入登入服務(wù)器的用戶名和密碼,這使數(shù)據(jù)拷貝變得不是很方便,而設(shè)置密鑰可是省略輸入密碼這一步驟。具體命令如下:
cd/.ssh
ssh-keygen-t rsa
將id_rsa文件中的密鑰拷貝到另一臺(tái)服務(wù)器的相應(yīng)位置,就可以實(shí)現(xiàn)兩臺(tái)服務(wù)器數(shù)據(jù)自由傳輸。
圖2 內(nèi)網(wǎng)與外網(wǎng)
設(shè)置密鑰傳輸數(shù)據(jù)僅限于內(nèi)網(wǎng)的服務(wù)器和臺(tái)式機(jī)之間而外網(wǎng)傳輸可以向任意一臺(tái)聯(lián)網(wǎng)的計(jì)算機(jī)傳輸數(shù)據(jù),傳輸數(shù)據(jù)的命令為
set file_name=igs$week$dow.sp3
set HOST="999.999.0.1"
set USER="user_name"
set PASS='secret'
ftp -inv $HOST ?EOF
user $USER $PASS
put $file_name
bye
EOF
該命令與mget命令相似,首先登入對(duì)方服務(wù)器,再使用put命令上傳。
若是想要將腳本和軟件每天都定時(shí)運(yùn)行,人工方法會(huì)很繁瑣,因此,可以考慮將其加載為自動(dòng)化運(yùn)行。將需要自動(dòng)運(yùn)行的腳本寫入一個(gè)新文件auto當(dāng)中:
30*/1 * * */bin/csh/root/shell/get-hourly>/root/log/get.log 2>&1
該命令的時(shí)間“30 */1 * * *”為每年、每月、每天的每小時(shí)30分運(yùn)行“get_hourly”腳本,由于自動(dòng)運(yùn)行全部在后臺(tái),不會(huì)輸出任何顯示信息,因此將其運(yùn)行中輸出的信息通過(guò)“>/root/log/get.log 2>&1”賦給一個(gè)日志文件,方便檢查運(yùn)行的狀態(tài)及出現(xiàn)的錯(cuò)誤。將需要自動(dòng)運(yùn)行的命令全部寫好后,執(zhí)行“crontab auto”命令,將其加載到后臺(tái)中,命令到運(yùn)行時(shí)間就可以自動(dòng)運(yùn)行。為了防止自動(dòng)運(yùn)行的腳本到了規(guī)定時(shí)間還沒(méi)有結(jié)束而影響其他的進(jìn)程,可以用“kill”命令將其強(qiáng)制結(jié)束。
自動(dòng)運(yùn)行的情況只能在輸出的log文件中查看,不能實(shí)時(shí)的發(fā)現(xiàn)錯(cuò)誤并進(jìn)行改正??梢栽陉P(guān)鍵步驟使用飛信進(jìn)行報(bào)錯(cuò)提醒,若是運(yùn)行出現(xiàn)問(wèn)題,飛信就會(huì)發(fā)送短信到指定的手機(jī)上。先安裝Linux系統(tǒng)版的飛信,再利用以下腳本進(jìn)行短信錯(cuò)誤預(yù)警:
set file_name=check_file
set lstop='cat $file_name | grep ’ERROR’
if("$lstop"=="")then
echo $file_name is Normal End>/root/log/file.log 2>&1
else
echo $file_name’ is not Normal End>/root/log/file.log 2>&1
/opt/fx/fetion -mobile=188****3047 -pwd=billgis3d -to=188****3048 -msg-utf8=$file_name’ is error’-debug
echo $?
endif
其中,需要檢查名為“check_file”的文件中是否有“ERROR”提示,若是沒(méi)有則表示運(yùn)行正常,若有,則一方面向log文件輸出文件不正常,一方面登錄飛信,向負(fù)責(zé)該文件生成的負(fù)責(zé)人發(fā)送短信。
本文根據(jù)作者的實(shí)際工作經(jīng)驗(yàn),總結(jié)了Linux Shell在衛(wèi)星定軌軟件設(shè)計(jì)中的應(yīng)用,主要有數(shù)據(jù)下載與合并、文件傳輸、自動(dòng)運(yùn)行與報(bào)錯(cuò)等,可以為從事衛(wèi)星導(dǎo)航定位領(lǐng)域的科研人員或工作人員提供參考。但本文介紹的只是利用Cshell語(yǔ)言作為工具,本文提到的功能也可以用其他的語(yǔ)言實(shí)現(xiàn),這里僅是提供一種思路和手段。
[1]劉文峰,李程遠(yuǎn),李善平.嵌入式Linux操作系統(tǒng)的研究[J].浙江大學(xué)學(xué)報(bào)·工學(xué)版,2004,38(4): 447-452.
[2]鄒 勇,王 青,李明樹.Linux內(nèi)核的實(shí)施支持的研究與實(shí)現(xiàn)[J].計(jì)算機(jī)研究與發(fā)展,2002,39(4): 466-472.
[3]劉善平,劉文峰,王煥龍,等.Linux與嵌入式系統(tǒng)[M].北京:清華大學(xué)出版社,2003.
[4]景月娥.衛(wèi)星定軌可視化軟件的實(shí)現(xiàn)與應(yīng)用研究[D].西安: 國(guó)家授時(shí)中心,2011.
[5]閆生超.基于BASH腳本的Unix環(huán)境下多組件部署管理框架[J].計(jì)算機(jī)系統(tǒng)應(yīng)用,2012,21(10): 61-65.
[6]白 云,喻 莉,謝長(zhǎng)生.一個(gè)基于Bash的輕量級(jí)構(gòu)建系統(tǒng)的設(shè)計(jì)與實(shí)現(xiàn)[J].計(jì)算機(jī)科學(xué),2013,40(11): 8-12.