Shell實現Unix進程間資訊交換的幾種方法

來源:互聯網
上載者:User

本文將介紹在SCO OpenServer5.0.5系統中使用shell語言來實現進程間資訊交換的幾種方法: 
使用具名管道實現進程間資訊交換 
使用kill命令和trap語句實現進程間資訊交換 
使用點命令“.”實現進程間資訊交換 
使用export語句實現父進程對子進程的資訊傳遞 
一、使用具名管道

具名管道是一種先進先出FIFO)的資料結構,它允許兩個進程通過管道聯結實現資訊交換。在Unix系統中,具名管道是一種特殊類型的檔案,因此可以對具名管道進行讀寫操作;當然,同樣也會有讀寫和執行等許可權的限制。 
通過下面的命令可以建立一個具名管道:
/etc/mknod pipe_name p 
其中“pipe_name”是要建立的具名管道的名字,參數p 必須出現在具名管道名字之後。 
具名管道檔案被建立後,一些進程就可以不斷地將資訊寫入具名管道檔案裡,而另一些進程也可以不斷地從具名管道檔案中讀取資訊。對具名管道檔案的讀寫操作是可以同時進行的。下面的例子顯示具名管道的工作過程。 
進程A、B、C中啟動並執行程式只是一條簡單的echo命令,它們不斷地把資訊寫入到具名管道檔案/tmp/pipe1中。與此同時,程式中的“read msg” 命令不斷地從具名管道檔案/tmp/pipe1中讀取這些資訊,從而實現這些進程間的資訊交換。 
程式執行時,首先建立具名管道檔案,此時程式處於等待狀態,直到A、B、C進程中某一個進程往具名管道中寫入資訊時,程式才繼續往下執行。使用rm命令可以刪除具名管道檔案從而清除已設定的具名管道。 
下面是一個用於記錄考勤的例子: 
在主機上啟動並執行程式/tmp/text產生具名管道/tmp/pipe1,並不斷地從具名管道中讀取資訊送螢幕上顯示。 
/tmp/text程式:
if [ ! -p /tmp/pipe1 ]
then
 /etc/mknode /tmp/pipe1 p
fi
while :
do
 read msg
 if [ “$msg" = “" ]
 then
continue
 else
echo “$msg"
 fi
done < /tmp/pipe1
在終端上啟動並執行是僱員簽到程式/tmp/text1。每個僱員在任何一台終端上鍵入自己的名字或代碼,程式/tmp/text1將把這個名字連同當時的簽到時間送入具名管道。 
/tmp/text1程式:
tty=‘who am I | awk ‘{print $2}’’
while :
do
 echo “Enter your name: \c" > /dev/$tty
 read name
 today=‘date’
 echo “$name\t$today"
 done > /tmp/pipe1
當僱員從終端上輸入自己的姓名後,運行/tmp/text程式的主機將顯示類似下面的結果: 
wang Thu Jan 28 09:29:26 BTJ 1999
he Thu Jan 28 09:29:26 BTJ 1999
cheng Thu Jan 28 09:30:26 BTJ 1999
zhang Thu Jan 28 09:31:26 BTJ 1999
二、使用kill命令和trap語句

在Unix系統中,當檢測到一個異常的內部狀態,或者硬體及外部裝置發出請求,或者執行某些指令時,將會向系統中的進程發出訊號報告事件產生。當進程捕獲到這些訊號後,系統便轉去執行預先設定的預設程式,完成指定的動作;這些預先設定的預設程式稱之為訊號的系統陷阱。 
在shell中,使用trap語句為訊號設定新的陷阱。當shell 捕獲到一個訊號時訊號11除外,因為shell本身要利用這個訊號進行記憶體配置),它將這個訊號傳遞給所有當前正在執行的程式父程式和子程式),並分別執行父程式和子程式中已設定的訊號陷阱。一旦陷阱程式執行結束,便返回中斷點,繼續執行原來的程式流程。 
trap語句的基本格式:
trap command_list signal_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。 
程式slave2執行情況與slave1相似。 
程式master也是首先設定訊號15的陷阱,然後把自己的當前進程寫入檔案/tmp/pro_list。在取得所有slave程式進程號後,向這些slave程式發出訊號15,然後進入迴圈等待。當接收到slave1或slave2發出的訊號15時,執行陷阱程式,顯示相關資訊,殺死所有slave進程,清空檔案/tmp/pro_list,然後退出。 
程式/tmp/slave1:
slave() {
 echo “slave1 has received sighal from master"
 echo “Request master to kill slave1 process"
 kill -15 $master_pid
}
trap slave 15
echo “slave1_pid $$" >> /tmp/pro_list
sleep 1
while :
do
 master_pid=‘awk ’$1 ~/master/
  {print $2}‘/tmp/pro_list’
 if [ “$master_pid" != “" ]
 then break
 fi
done
while :
do
 sleep 1
done
程式/tmp/slave2:
slave() {
 echo “slave2 has received sighal from master"
 echo “Request master to kill slave2 process"
 kill -15 $master_pid
}
trap slave 15
echo “slave2_pid $$" >> /tmp/pro_list
sleep 1
while :
do
 master_pid=‘awk ’$1 ~/master/ 
  {print $2}‘/tmp/pro_list’
 if [ “$master_pid" != “" ]
 then break
 fi
done
while :
do
 sleep 1
done
程式/tmp/master:
kill_slave() {
 echo “Master has received signals
from slave processes"
 echo “End all slave processes"
 kill -9 $slave_list
>/tmp/pro_list
exit 0
}
trap kill_slave 15
echo “master_pid $$" >> /tmp/pro_list
sleep 1
slave_list=‘awk ’$1 ~/slave/ 
{print $2}‘/tmp/pro_list’
echo “Current slave processes are:"
echo “$slave_list"
kill -15 $slave_list
while :
do
 sleep 1
done
執行程式:
$ cd /tmp
$ ./slave1&
15638
$ ./slave2&
16831
$ ./master
Current slave processes are:
15638
16831
slave1 has received signal 15 from master
Request master to kill slave1 process
slave2 has received signal 15 from master
Request master to kill slave2 process
Master has received signals from slave processes
End all slave processes
15638 Killed
16831 Killed

三、使用點命令“.”

“.”點命令是shell的一個內部命令,它從指定的shell 檔案中讀入所有命令語句並在當前進程中執行。 因此當多個shell進程父子進程或無關進程均可)共用一組變數值時,就可以將這些變數指派陳述式定義到一個shell檔案裡,並在需要這些變數值的程式中使用點語句來引用這個shell檔案,從而實現變數值共用對這些變數值的修改僅涉及到這個shell檔案)。但要注意的是,這個shell檔案不能包括含有位置參數的語句,即不能接受$1、$2等命令列參數。 
下面是一個在超市中發布每日商品價格的示範程式片段。發布每日商品價格統一由程式/tmp/jiage來執行,它為每種商品價格賦值,並把相應的指派陳述式寫入檔案/tmp/jiagebiao中。在各終端上啟動並執行收款程式/tmp/shoukuan將讀入檔案 /tmp/jiagebiao中所有指派陳述式並在當前進程中執行,從而擷取在程式/tmp/jiage中設定的價格。 
價格設定程式/tmp/jiage: 
echo “Enter the price of chicken,
  duck and fish: \c"
read chicken duck fish
exec 3>/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 “Enter the trade name and
 quantities or input q to sum: \c"
read trade$count quantity$count
eval a=\$trade$count
if [ “$a" = “q" ]
then if [ $count -gt 0 ]
then
count=‘expr $count - 1’
fi
break
fi
count=‘expr $count + 1 ’
done
echo “\n‘date’"
echo “trade name\tquantity\tsum"
while [ “$count" -ge 0 ]
do
 eval trade=“\${trade$count}"
 eval trade_price=“${trade}_price"
 eval danjia=\${$trade_price}
 eval quantity=“\${quantity$count}"
 sum=‘echo “scale=2; $danjia
 *$quantity"|bc’
 echo “$trade\t\t$quantity\t\t$sum"
 count=‘expr $count - 1 ’
done
在終端上執行程式/tmp/shoukuan將有如下顯示: 
Enter the trade name and quantities
or input q to sum: chicken 2
Enter the trade name and quantities
or input q to sum: fish 3
Enter the trade name and quantities
or input q to sum: duck 4
Enter the trade name and quantities 
 or input q to sum: q
Thu Jan 28 09:29:29 BJT 1999:
duck 4 10
fish 3 12.6
chicken 2 10.8
四、使用export語句

通常shell變數是局部變數,無論是通過賦值操作還是通過命令賦值,其變數值只在當前進程中有效。但是經過export語句說明的shell變數就成為一個全域性變數,其變數名和變數值可以傳遞給子進程及其後代進程。在子進程中可以修改這個變數的值,但並不影響這個變數在父進程中的取值。 
下面的例子中,父進程/tmp/text)將賦值後的變數 pro_name傳遞給子進程/tmp/text_child),在子進程中對變數pro_name所賦的新值並不影響父進程中該變數的值。 
/tmp/text程式:
pro_name=“PARENT"
echo “The variable pro_name is
$pro_name in parent process"
export pro_name
/tmp/text_child
echo “The variable pro_name is
$pro_name after retund to parent process"
/tmp/text_child程式:
echo“The variable pro_name ($pro_name) is
 transmited to child process"
pro_name=“CHILD"
echo “To change the variable pro_name to 
  $pro_name in child process"
執行程式/tmp/text:
$ /tmp/text
The variable pro_name is PARENT in parent process
The variable pro_name (PARENT)
is transmited to child process
To change the variable pro_name to CHILD in child process
The variable pro_name is PARENT after retund to parent process


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.