本文將介紹在SCOOpenServer5.0.5系統中使用shell語言來實現進程間信息交換的幾種方法:
使用命名管道實現進程間信息交換
使用kill命令和trap語句實現進程間信息交換
使用點命令“.”實現進程間信息交換
使用export語句實現父進程對子進程的信息傳遞
一、使用命名管道
命名管道是一種先進先出(FIFO)的數據結構,它允許兩個進程通過管道聯接實現信息交換。
在Unix系統中,命名管道是一種特殊類型的文件,因此可以對命名管道進行讀寫操作;當然,同樣
也會有讀寫和執行等權限的限制。
通過下面的命令可以創建一個命名管道:
/etc/mknodpipe_namep
其中“pipe_name”是要創建的命名管道的名字,參數p必須出現在命名管道名字之後。
命名管道文件被創建後,一些進程就可以不斷地將信息寫入命名管道文件裡,而另一些進程也
可以不斷地從命名管道文件中讀取信息。對命名管道文件的讀寫操作是可以同時進行的。下面的例子
顯示命名管道的工作過程。
進程A、B、C中運行的程序只是一條簡單的echo命令,它們不斷地把信息寫入到命名管道文件
/tmp/pipe1中。與此同時,程序中的“readmsg”命令不斷地從命名管道文件/tmp/pipe1中讀取這些
信息,從而實現這些進程間的信息交換。
程序執行時,首先創建命名管道文件,此時程序處於等待狀態,直到A、B、C進程中某一個進程往
命名管道中寫入信息時,程序才繼續往下執行。使用rm命令可以刪除命名管道文件從而清除已設置的
命名管道。
下面是一個用於記錄考勤的例子:
在主機上運行的程序/tmp/text產生命名管道/tmp/pipe1,並不斷地從命名管道中讀取信息送屏幕
上顯示。
/tmp/text程序:
if[!-p/tmp/pipe1]
then
/etc/mknode/tmp/pipe1p
fi
while:
do
readmsg
if[“$msg"=“"]
then
continue
else
echo“$msg"
fi
done
在終端上運行的是雇員簽到程序/tmp/text1。每個雇員在任何一台終端上鍵入自己的名字或代碼,
程序/tmp/text1將把這個名字連同當時的簽到時間送入命名管道。
/tmp/text1程序:
tty=‘whoamI|awk‘{print$2}’’
while:
do
echo“Enteryourname:\c">/dev/$tty
readname
today=‘date’
echo“$name\t$today"
done>/tmp/pipe1
當雇員從終端上輸入自己的姓名後,運行/tmp/text程序的主機將顯示類似下面的結果:
wangThuJan2809:29:26BTJ1999
heThuJan2809:29:26BTJ1999
chengThuJan2809:30:26BTJ1999
zhangThuJan2809:31:26BTJ1999
二、使用kill命令和trap語句
在Unix系統中,當檢測到一個異常的內部狀態,或者硬件及外部設備發出請求,或者執行某些指令時,
將會向系統中的進程發出信號報告事件產生。當進程捕獲到這些信號後,系統便轉去執行預先設定的默認
程序,完成指定的動作;這些預先設定的默認程序稱之為信號的系統陷阱。
在shell中,使用trap語句為信號設置新的陷阱。當shell捕獲到一個信號時(信號11除外,因為
shell本身要利用這個信號進行內存分配),它將這個信號傳遞給所有當前正在執行的程序
(父程序和子程序),並分別執行父程序和子程序中已設置的信號陷阱。一旦陷阱程序執行結束,便返
回中斷點,繼續執行原來的程序流程。
trap語句的基本格式:
trapcommand_listsignal_list
command_list:由一個或多個命令(或命令組)構成的命令列表。當命令列表中含有多個命令時要
用單引號或雙引號括起來,並且各命令間要用分號隔開。
signal_list:由一個或多個信號值構成的信號列表,各信號值間要用空格分開。
在一個shell程序(父程序)中重新設置信號的陷阱並不改變被這個程序所調用的子程序中同名信號
的陷阱。同樣,在子程序中設置的信號陷阱也不影響父程序中同名信號的陷阱。
shell在讀取trap語句時,要掃描一次命令列表,以便設置陷阱。在捕獲信號後,shell再次掃描命令
列表,執行已設置好的陷阱程序(命令或命令組)。因此,如果命令列表中含有變量置換或命令置換表達
式,shell在第一次掃描命令列表時就會用當前的變量值或命令結果置換這些表達式,使得在捕獲到信號而
去執行陷阱程序時,陷阱程序已經不是原來設置的陷阱程序了。為了避免這種情況發生,使用單引號而不是
使用雙引號把trap語句中含有變量置換或命令置換表達式的命令列表括起來;因為單引號可以消除所有字符
的特殊含義,這樣避免了shell在第一次掃描時執行任何置換或替代操作,直到命令列表被執行時才進行置
換或替代。
向一個程序或進程傳遞信號方法很多,比如在程序執行時按下Ctrl+c鍵或Del鍵,將向程序傳遞一個
SIGINT信號,執行該信號的系統陷阱將終止程序執行。使用kill命令傳遞信號是shell語言編程中最為常用
的方法。
kill命令的基本格式是:
kill[-signal]PID
通常kill命令用來終止一個進程。但如果使用了帶有短劃線“-”的信號作為參數時,kill命令就發送
該信號給PID指示的一個或多個進程,而不是終止進程。當trap語句捕獲到這個信號後便執行設定的信號陷阱
程序,實現進程間的相互通訊。
下面的例子顯示了程序master和slave1、slave2間如何利用信號機制實現相互通訊的。首先在後台運行
程序slave1和slave2,然後運行程序master。在文件/tmp/pro_list中記錄了這三個程序的進程號。
程序slave1首先設置信號15的陷阱,然後把自己的當前進程寫入文件/tmp/pro_list;在獲得master進程
號後,進入循環狀態。當接收到master發出的信號15時,執行陷阱程序,顯示相關信息後,向master發出信
號15。
slave1hasreceivedsignal15frommaster
Requestmastertokillslave1process
slave2hasreceivedsignal15frommaster
Requestmastertokillslave2process
Masterhasreceivedsignalsfromslaveprocesses
Endallslaveprocesses
15638Killed
16831Killed
$
三、使用點命令“.”
“.”點命令是shell的一個內部命令,它從指定的shell文件中讀入所有命令語句並在當前進程
中執行。因此當多個shell進程(父子進程或無關進程均可)共享一組變量值時,就可以將這些變量
賦值語句定義到一個shell文件裡,並在需要這些變量值的程序中使用點語句來引用這個shell文件,
從而實現變量值共享(對這些變量值的修改僅涉及到這個shell文件)。但要注意的是,這個shell文
件不能包括含有位置參數的語句,即不能接受$1、$2等命令行參數。
下面是一個在超市中發布每日商品價格的示范程序片段。發布每日商品價格統一由程序/tmp/jiage
來執行,它為每種商品價格賦值,並把相應的賦值語句寫入文件/tmp/jiagebiao中。在各終端上運行的
收款程序/tmp/shoukuan將讀入文件/tmp/jiagebiao中所有賦值語句並在當前進程中執行,從而獲取在
程序/tmp/jiage中設定的價格。
價格設定程序/tmp/jiage:
echo“Enterthepriceofchicken,
duckandfish:\c"
readchickenduckfish
exec3>/tmp/jiagebiao
echo“chicken_price=$chicken">&3
echo“duck_price=$duck">&3
echo“fish_price=$fish">&3
執行/tmp/jiage程序後,文件/tmp/jiagebiao中將有如下內容:
chicken_price=5.4
duck_price=2.5
fish_price=4.2
收款程序/tmp/shoukuan:
./tmp/jiagebiao
count=0
while:
do
echo“Enterthetradenameand
quantitiesorinputqtosum:\c"
readtrade$countquantity$count
evala=\$trade$count
if[“$a"=“q"]
thenif[$count-gt0]
then
count=‘expr$count-1’
fi
break
fi
count=‘expr$count+1’
done
echo“\n‘date’"
echo“tradename\tquantity\tsum"
while[“$count"-ge0]
do
evaltrade=“\${trade$count}"
evaltrade_price=“${trade}_price"
evaldanjia=\${$trade_price}
evalquantity=“\${quantity$count}"
sum=‘echo“scale=2;$danjia
*$quantity"|bc’
echo“$trade\t\t$quantity\t\t$sum"
count=‘expr$count-1’
done
在終端上執行程序/tmp/shoukuan將有如下顯示:
Enterthetradenameandquantities
orinputqtosum:chicken2
Enterthetradenameandquantities
orinputqtosum:fish3
Enterthetradenameandquantities
orinputqtosum:duck4
Enterthetradenameandquantities
orinputqtosum:q
ThuJan2809:29:29BJT1999:
duck410
fish312.6
chicken210.8
四、使用export語句
通常shell變量是局部變量,無論是通過賦值操作還是通過命令賦值,其變量值只在當前進程中
有效。但是經過export語句說明的shell變量就成為一個全局性變量,其變量名和變量值可以傳遞給
子進程及其後代進程。在子進程中可以修改這個變量的值,但並不影響這個變量在父進程中的取值。
下面的例子中,父進程(/tmp/text)將賦值後的變量pro_name傳遞給子進程(/tmp/text_child),
在子進程中對變量pro_name所賦的新值並不影響父進程中該變量的值。
/tmp/text程序:
pro_name=“PARENT"
echo“Thevariablepro_nameis
$pro_nameinparentprocess"
exportpro_name
/tmp/text_child
echo“Thevariablepro_nameis
$pro_nameafterretundtoparentprocess"
/tmp/text_child程序:
echo“Thevariablepro_name($pro_name)is
transmitedtochildprocess"
pro_name=“CHILD"
echo“Tochangethevariablepro_nameto
$pro_nameinchildprocess"
執行程序/tmp/text:
$/tmp/text
Thevariablepro_nameisPARENT
inparentprocess
Thevariablepro_name(PARENT)
istransmitedtochildprocess
Tochangethevariablepro_nametoCHILD
inchildprocess
Thevariablepro_nameisPARENT
afterretundtoparentprocess
$