• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            興海北路

            ---男兒仗劍自橫行
            <2008年3月>
            2425262728291
            2345678
            9101112131415
            16171819202122
            23242526272829
            303112345

            統(tǒng)計

            • 隨筆 - 85
            • 文章 - 0
            • 評論 - 17
            • 引用 - 0

            常用鏈接

            留言簿(6)

            隨筆分類

            隨筆檔案

            收藏夾

            全是知識啊

            搜索

            •  

            最新評論

            閱讀排行榜

            評論排行榜

            shell編程范例之進程的操作
            by falcon<zhangjinw@gmail.com>
            2008-02-21

                這一小節(jié)寫了很久,到現(xiàn)在才寫完。本來關(guān)注的內(nèi)容比較多,包括程序開發(fā)過程的細節(jié)、ELF格式的分析、進程的內(nèi)存映像等,后來搞得“雪球越滾越大”,甚至 脫離了shell編程關(guān)注的內(nèi)容。所以呢,想了個小辦法,“大事化小,小事化了”,把涉及到的內(nèi)容分成如下幾個部分:
                1、把VIM打造成源代碼編輯器(源代碼編輯過程:用VIM編輯代碼的一些技巧)
                2、GCC編譯的背后 第一部分:預(yù)處理和編譯 第二部分:匯編和鏈接(編譯過程:預(yù)處理、編譯、匯編、鏈接)
                3、程序執(zhí)行的那一剎那 (執(zhí)行過程:當(dāng)我們從命令行輸入一個命令之后)
                4、進程的內(nèi)存映像 (進程加載過程:程序在內(nèi)存里是個什么樣子)
                5、動態(tài)符號鏈接的細節(jié)(動態(tài)鏈接過程:函數(shù)puts/printf的地址在哪里)
                6、代碼測試、調(diào)試與優(yōu)化小結(jié)(程序開發(fā)過后:內(nèi)存溢出了嗎?有緩沖區(qū)溢出?代碼覆蓋率如何測試呢?怎么調(diào)試匯編代碼?有哪些代碼優(yōu)化技巧和方法呢?)
                7、    8、進程和進程的基本操作(本小節(jié))
                呵呵,好多。終于可以一部分一部分地完成了,不會再有一種對著一個大蛋糕卻不知道如何下口的尷尬了。
                進程作為程序真正發(fā)揮作用時的“形態(tài)”,我們有必要對它的一些相關(guān)操作非常熟悉,這一節(jié)主要描述進程相關(guān)的概念和操作,將介紹包括程序、進程、作業(yè)等基本概念以及進程狀態(tài)查詢、進程通信等相關(guān)的基本操作等。

            1、什么是程序,什么又是進程

                程序是指令的集合,而進程則是程序執(zhí)行的基本單元。為了讓程序完成它的工作,我們必須讓程序運行起來成為進程,進而利用處理器資源,內(nèi)存資源,進行各種I/O操作,從而完成某項指定的工作。
                在這個意思上說,程序是靜態(tài)的,而進程則是動態(tài)的。
                而進程有區(qū)別于程序的地方還有,進程除了包含程序文件中的指令數(shù)據(jù)意外,還需要在內(nèi)核中有一個數(shù)據(jù)結(jié)構(gòu)用以存放特定進程的相關(guān)屬性,以便內(nèi)核更好的管理和調(diào)度進程,從而完成多進程協(xié)作的任務(wù)。因此,從這個意義上可以說“高于”程序,超出了程序指令本身。
                如果進行過多進程程序的開發(fā),你又會發(fā)現(xiàn),一個程序可能創(chuàng)建多個進程,通過多個進程的交互完成任務(wù)。在Linux下,多進程的創(chuàng)建通常是通過fork系統(tǒng)調(diào)用實現(xiàn)的。從這個意義上來說程序則”包含”了進程。
                另外一個需要明確的是,程序可以由多種不同的程序語言描述,包括C語言程序、匯編語言程序和最后編譯產(chǎn)生的機器指令等。
               
                下面我們簡單討論一下Linux下面如何通過shell進行進程的相關(guān)操作。

            2、進程的創(chuàng)建

                通常在命令行鍵入某個程序文件名以后,一個進程就被創(chuàng)建了。例如,

            Quote:

            $ sleep 100 &            #讓sleep程序在后臺運行
            [1] 9298
            $ pidof sleep             #用pidof可以查看指定程序名的進程ID
            9298
            $ cat /proc/9298/maps    #查看進程的內(nèi)存映像
            08048000-0804b000 r-xp 00000000 08:01 977399     /bin/sleep
            0804b000-0804c000 rw-p 00003000 08:01 977399     /bin/sleep
            0804c000-0806d000 rw-p 0804c000 00:00 0          [heap]
            b7c8b000-b7cca000 r--p 00000000 08:01 443354    
            ...
            bfbd8000-bfbed000 rw-p bfbd8000 00:00 0          [stack]
            ffffe000-fffff000 r-xp 00000000 00:00 0          [vdso]


                當(dāng)一個程序被執(zhí)行以后,程序被加載到內(nèi)存中,成為了一個進程。上面顯示了該進程的內(nèi)存映像(虛擬內(nèi)存),包括程序指令、數(shù)據(jù),以及一些用于存放程命令行參數(shù)、環(huán)境變量的棧空間,用于動態(tài)內(nèi)存申請的堆空間都被分配好了。
                關(guān)于程序在命令行執(zhí)行過程的細節(jié),請參考《Linux命令行下程序執(zhí)行的那一剎那》。

                實際上,創(chuàng)建一個進程,也就是說讓程序運行,還有其他的辦法,比如,通過一些配置讓系統(tǒng)啟動時自動啟動我們的程序(具體參考"man init"),或者是通過配置crond(或者at)讓它定時啟動我們的程序。除此之外,還有一個方式,那就是編寫shell腳本,把程序?qū)懭胍粋€腳本文 件,當(dāng)執(zhí)行腳本文件時,文件中的程序?qū)⒈粓?zhí)行而成為進程。這些方式的細節(jié)就不介紹了,下面介紹如何查看進程的屬性。

                需要補充一點的是,在命令行下執(zhí)行程序時,我們可以通過ulimit內(nèi)置命令來設(shè)置進程可以利用的資源,比如進程可以打開的最大文件描述符個數(shù),最大的棧空間,虛擬內(nèi)存空間等。具體用法見"help ulimit"。

            3、查看進程的屬性和狀態(tài)

                我們可以通過ps命令查看進程的相關(guān)屬性和狀態(tài),這些信息包括進程所屬用戶,進程對應(yīng)的程序,進程對cpu和內(nèi)存的使用情況等信息。熟悉如何查看它們有助于我們進行相關(guān)的統(tǒng)計分析和進一步的操作。

            Quote:

            $ ps -ef #查看系統(tǒng)所有當(dāng)前進程的屬性
            $ ps -C init #查看命令中包含某個指定字符的程序?qū)?yīng)的進程,進程ID是1,TTY為?表示和終端沒有關(guān)聯(lián)
              PID TTY          TIME CMD
                1 ?        00:00:01 init
            $ ps -U falcon #選擇某個特定用戶啟動的進程
            $ ps -e -o "%C %c"  #可以按照指定格式輸出指定內(nèi)容,這里會輸出命令名和cpu使用率
            $ ps -e -o "%C %c" | sort -u -k1 -r | head -5  #這樣則會打印cpu使用率最高的前4個程序
             7.5 firefox-bin
             1.1 Xorg
             0.8 scim-panel-gtk
             0.2 scim-bridge
            $ ps -e -o "%z %c" | sort -n -k1 -r | head -5  #使用虛擬內(nèi)存最大的5個進程
            349588 firefox-bin
             96612 xfce4-terminal
             88840 xfdesktop
             76332 gedit
             58920 scim-panel-gtk


                由于系統(tǒng)所有進程之間都有“親緣”關(guān)系,所以可以通過pstree查看這種關(guān)系,
            Quote:

            $ pstree #打印系統(tǒng)進程調(diào)用樹,可以非常清楚地看到當(dāng)前系統(tǒng)中所有活動進程之間的調(diào)用關(guān)系


                動態(tài)查看進程信息,  
            Quote:

            $ top


                該命令最大的特點是可以動態(tài)的查看進程的信息,當(dāng)然,它還提供了一些有用的參數(shù),比如-S可以按照累計執(zhí)行時間的大小排序查看,也可以通過-u查看指定用戶啟動的進程等。

                感覺有上面幾個命令來查看進程的信息就差不多了,下面來討論一個有趣的問題:如何讓一個程序在同一時間只有一個在運行。
                這意味著當(dāng)一個程序正在被執(zhí)行時,它將不能再被啟動。那該怎么做呢?
                假如一份相同的程序被復(fù)制成了很多份,并且具有不同的文件名被放在不同的位置,這個將比較糟糕,所以我們考慮最簡單的情況,那就是這份程序在整個系統(tǒng)上是唯一的,而且名字也是唯一的。這樣的話,我們有哪些辦法來回答上面的問題呢?
                總的機理是:在這個程序的開頭檢查自己有沒有執(zhí)行,如果執(zhí)行了則停止否則繼續(xù)執(zhí)行后續(xù)代碼。
                策略則是多樣的,由于前面的假設(shè)已經(jīng)保證程序文件名和代碼的唯一性,所以
          1. 通過ps命令打印找出當(dāng)前的所有進程對應(yīng)的程序名,逐個與自己的程序名比較,如果已經(jīng)有,那么說明自己已經(jīng)運行了。


            Code:

            [Ctrl+A Select All]


          2. 每次運行時先在指定位置檢查是否存在一個保存自己進程ID的文件,如果不存在,那么繼續(xù)執(zhí)行,如果存在,那么查看該進程ID是否正在運行,如果在,那么退出,否則往該文件重新寫的新的進程ID,并繼續(xù)。



            Code:

            [Ctrl+A Select All]


                更多實現(xiàn)策略自己盡情的發(fā)揮吧!

            4、調(diào)整進程的優(yōu)先級

                在保證每個進程都能夠順利執(zhí)行外,為了讓某些任務(wù)優(yōu)先完成,那么系統(tǒng)在進行進程調(diào)度時就會采用一定的調(diào)度辦法,比如常見的有按照優(yōu)先級的時間片輪轉(zhuǎn)的調(diào)度算法。這種情況下,我們可以通過renice調(diào)整正在運行的程序的優(yōu)先級,例如,

            Quote:

            $ ps -e -o "%p %c %n" | grep xfs #打印的信息分別是進程ID,進程對應(yīng)的程序名,優(yōu)先級
             5089 xfs               0
            $ renice 1 -p 5089
            renice: 5089: setpriority: Operation not permitted
            $ sudo renice 1 -p 5089   #需要權(quán)限才行
            [sudo] password for falcon:
            5089: old priority 0, new priority 1
            $ ps -e -o "%p %c %n" | grep xfs  #再看看,優(yōu)先級已經(jīng)被調(diào)整過來了
             5089 xfs               1



            5、結(jié)束進程

                既然可以通過命令行執(zhí)行程序,創(chuàng)建進程,那么也有辦法結(jié)束它。我們可以通過kill命令給用戶自己啟動的進程發(fā)送一定信號讓進程終止,當(dāng)然“萬能”的root幾乎可以kill所有進程(除了init之外)。例如,

            Quote:

            $ sleep 50 &   #啟動一個進程
            [1] 11347
            $ kill 11347


                kill命令默認會發(fā)送終止信號(SIGTERM)給程序,讓程序退出,但是kill還可以發(fā)送其他的信號,這些信號的定義我們可以通過man 7 signal查看到,也可以通過kill -l列出來。
            Quote:

            $ man 7 signal
            $ kill -l
             1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL
             5) SIGTRAP      6) SIGABRT      7) SIGBUS       8) SIGFPE
             9) SIGKILL     10) SIGUSR1     11) SIGSEGV     12) SIGUSR2
            13) SIGPIPE     14) SIGALRM     15) SIGTERM     16) SIGSTKFLT
            17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP
            21) SIGTTIN     22) SIGTTOU     23) SIGURG      24) SIGXCPU
            25) SIGXFSZ     26) SIGVTALRM   27) SIGPROF     28) SIGWINCH
            29) SIGIO       30) SIGPWR      31) SIGSYS      34) SIGRTMIN
            35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3  38) SIGRTMIN+4
            39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
            43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12
            47) SIGRTMIN+13 48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14
            51) SIGRTMAX-13 52) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10
            55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7  58) SIGRTMAX-6
            59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
            63) SIGRTMAX-1  64) SIGRTMAX


                例如,我們用kill命令發(fā)送SIGSTOP信號給某個程序,讓它暫停,然后發(fā)送SIGCONT信號讓它繼續(xù)運行。

            Quote:

            $ sleep 50 &
            [1] 11441
            $ jobs
            [1]+  Running                 sleep 50 &
            $ kill -s SIGSTOP 11441   #這個等同于我們對一個前臺進程執(zhí)行CTRL+Z操作
            $ jobs
            [1]+  Stopped                 sleep 50
            $ kill -s SIGCONT 11441   #這個等同于之前我們使用bg %1操作讓一個后臺進程運行起來
            $ jobs
            [1]+  Running                 sleep 50 &
            $ kill %1                  #在當(dāng)前會話(session)下,也可以通過作業(yè)號控制進程
            $ jobs
            [1]+  Terminated              sleep 50


                可見kill命令為我們提供了非常好的功能,不過kill命令只能根據(jù)進程的ID或者作業(yè)來控制進程,所以pkill和killall給我們提供了更多選擇,它們擴展了通過程序名甚至是進程的用戶名來控制進程的方法。更多用法請參考它們的手冊。

                當(dāng)一個程序退出以后,如何判斷這個程序是正常退出還是異常退出呢?還記得Linux下,那個經(jīng)典"hello,world"程序嗎?在代碼的最后總是有條 “return 0”語句。這個“return 0”實際上是為了讓程序員來檢查進程是否正常退出的。如果進程返回了一個其他的數(shù)值,那么我們可以肯定的說這個進程異常退出了,因為它都沒有執(zhí)行到 “return 0”這條語句就退出了。
                那怎么檢查進程退出的狀態(tài),即那個返回的數(shù)值呢?
                在shell程序中,我們可以檢查這個特殊的變量$?,它存放了上一條命令執(zhí)行后的退出狀態(tài)。

            Quote:

            $ test1
            bash: test1: command not found
            $ echo $?
            127
            $ cat ./test.c | grep hello
            $ echo $?
            1
            $ cat ./test.c | grep hi
                    printf("hi, myself!\n");
            $ echo $?
            0


                貌似返回0成為了一個潛規(guī)則,雖然沒有標準明確規(guī)定,不過當(dāng)程序正常返回時,我們總是可以從$?中檢測到0,但是異常時,我們總是檢測到一個非0的值。這 就告訴我們在程序的最后我們最好是跟上一個exit 0以便任何人都可以通過檢測$?確定你的程序是否正常結(jié)束。如果有一天,有人偶爾用到你的程序,試圖檢查你的程序的退出狀態(tài),而你卻在程序的末尾莫名的返 回了一個-1或者1,那么他將會很苦惱,會懷疑自己的程序哪個地方出了問題,檢查半天卻不知所措,因為他太信任你了,竟然從頭至尾都沒有懷疑你的編程習(xí)慣 可能會與眾不同。

            6、進程通信

                為了便于設(shè)計和實現(xiàn),通常一個大型的任務(wù)都被劃分成較小的模塊。不同模塊之間啟動后成為進程,它們之間如何通信以便交互數(shù)據(jù),協(xié)同工作呢?在《UNIX環(huán) 境高級編程》一書中提到很多方法,諸如管道(無名管道和有名管道)、信號(signal)、報文(Message)隊列(消息隊列)、共享內(nèi)存 (mmap/munmap)、信號量(semaphore,主要是同步用,進程之間,進程的不同線程之間)、套接口(Socket,支持不同機器之間的進 程通信)等,而在shell編程里頭,我們通常直接用到的就有管道和信號等。下面主要介紹管道和信號機制在shell編程時候的一些用法。
               
               
          3. 無名管道(pipe):

                在Linux下,你可以通過"|"連接兩個程序,這樣就可以用它來連接后一個程序的輸入和前一個程序的輸出,因此被形象地叫做個管道。在C語言里頭,創(chuàng)建 無名管道非常簡單方便,用pipe函數(shù),傳入一個具有兩個元素的int型的數(shù)組就可以。這個數(shù)組實際上保存的是兩個文件描述符,父進程往第一個文件描述符 里頭寫入東西后,子進程可以從第一個文件描述符中讀出來。

                如果用多了命令行,這個管子"|"應(yīng)該會經(jīng)常用。比如我們在上面的演示中把ps命令的輸出作為grep命令的輸入,從而可以過濾掉一些我們感興趣的信息:

            Quote:

            $ ps -ef | grep init



                也許你會覺得這個“管子”好有魔法,竟然真地能夠鏈接兩個程序的輸入和輸出,它們到底是怎么實現(xiàn)的呢?實際上當(dāng)我們輸入這樣一組命令的時候,當(dāng)前解釋程序 會進行適當(dāng)?shù)慕馕觯亚懊嬉粋€進程的輸出關(guān)聯(lián)到管道的輸出文件描述符,把后面一個進程的輸入關(guān)聯(lián)到管道的輸入文件描述符,這個關(guān)聯(lián)過程通過輸入輸出重定向 函數(shù)dup(或者fcntl)來實現(xiàn)。

               
          4. 有名管道(named pipe):

                有名管道實際上是一個文件(無名管道也像一個文件,雖然關(guān)系到兩個文件描述符,不過只能一邊讀另外一邊寫),不過這個文件比較特別,操作時要滿足先進先 出,而且,如果試圖讀一個沒有內(nèi)容的有名管道,那么就會被阻塞,同樣地,如果試圖往一個有名管道里頭寫東西,而當(dāng)前沒有程序試圖讀它,也會被阻塞。下面看 看效果。

            Quote:

            $ mkfifo fifo_test    #通過mkfifo命令可以創(chuàng)建一個有名管道
            $ echo "fewfefe" > fifo_test    #試圖往fifo_test文件中寫入內(nèi)容,但是被阻塞,要另開一個終端繼續(xù)下面的操作
            $ cat fifo_test        #另開一個終端,記得,另開一個。試圖讀出fifo_test的內(nèi)容
            fewfefe



                在這里echo和cat是兩個不同的程序,在這種情況下,通過echo和cat啟動的兩個進程之間并沒有父子關(guān)系。不過它們依然可以通過有名管道通信。這 樣一種通信方式非常適合某些情況:例如有這樣一個架構(gòu),這個架構(gòu)由兩個應(yīng)用程序構(gòu)成,其中一個通過一個循環(huán)不斷讀取fifo_test中的內(nèi)容,以便判 斷,它下一步要做什么。如果這個管道沒有內(nèi)容,那么它就會被阻塞在那里,而不會死循環(huán)而耗費資源,另外一個則作為一個控制程序不斷地往fifo_test 中寫入一些控制信息,以便告訴之前的那個程序該做什么。下面寫一個非常簡單的例子。我們可以設(shè)計一些控制碼,然控制程序不斷的往fifo_test里頭寫 入,然后應(yīng)用程序根據(jù)這些控制碼完成不同的動作。當(dāng)然,也可以往fifo_test傳入除控制碼外的不同的數(shù)據(jù)。

            Quote:

            $ cat app.sh    #應(yīng)用程序的代碼
            #!/bin/bash

            FIFO=fifo_test
            while :;
            do
                            CI=`cat $FIFO`  #CI --> Control Info
                            case $CI in
                                            0) echo "The CONTROL number is ZERO, do something ..."
                                                    ;;
                                            1) echo "The CONTROL number is ONE, do something ..."
                                                    ;;
                                            *) echo "The CONTROL number not recognized, do something else..."
                                                    ;;
                            esac
            done
            $ cat control.sh    #控制程序的代碼
            #!/bin/bash

            FIFO=fifo_test
            CI=$1

            [ -z "$CI" ] && echo "the control info should not be empty" && exit

            echo $CI > $FIFO
            $ chmod +x app.sh control.sh    #修改這兩個程序的可執(zhí)行權(quán)限,以便用戶可以執(zhí)行它們
            $ ./app.sh            #在一個終端啟動這個應(yīng)用程序,在通過./control.sh發(fā)送控制碼以后查看輸出
            The CONTROL number is ONE, do something ...    #發(fā)送1以后
            The CONTROL number is ZERO, do something ...    #發(fā)送0以后
            The CONTROL number not recognized, do something else...    #發(fā)送一個未知的控制碼以后
            $ ./control.sh 1            #在另外一個終端,發(fā)送控制信息,控制應(yīng)用程序的工作
            $ ./control.sh 0            
            $ ./control.sh 4343



                這樣一種應(yīng)用架構(gòu)非常適合本地的多程序任務(wù)的設(shè)計,如果結(jié)合web cgi,那么也將適合遠程控制的要求。引入web cgi的唯一改變是,要把控制程序./control.sh放到web的cgi目錄下,并對它作一些修改,以使它符合CGI的規(guī)范,這些規(guī)范包括文檔輸出 格式的表示(在文件開頭需要輸出content-tpye: text/html以及一個空白行)和輸入?yún)?shù)的獲取(web輸入?yún)?shù)都存放在QUERY_STRING環(huán)境變量里頭)。因此一個非常簡單的CGI形式控 制程序?qū)㈩愃葡旅妗?br>


            Code:

            [Ctrl+A Select All]



                在實際使用的時候,請確保control.sh能夠訪問到fifo_test管道,并且有寫權(quán)限。這樣我們在瀏覽器上就可以這樣控制app.sh了。

            http://ipaddress_or_dns/cgi-bin/control.sh?0

                問號(?)后面的內(nèi)容即QUERY_STRING,類似之前的$1。

                這樣一種應(yīng)用對于遠程控制,特別是嵌入式系統(tǒng)的遠程控制很有實際意義。在去年的暑期課程上,我們就通過這樣一種方式來實現(xiàn)馬達的遠程控制。首先,我們實現(xiàn) 了一個簡單的應(yīng)用程序以便控制馬達的轉(zhuǎn)動,包括轉(zhuǎn)速,方向等的控制。為了實現(xiàn)遠程控制,我們設(shè)計了一些控制碼,以便控制馬達轉(zhuǎn)動相關(guān)的不同屬性。

                在C語言中,如果要用有名管道,和shell下的類似,只不過在讀寫數(shù)據(jù)的時候用read,write調(diào)用,在創(chuàng)建fifo的時候用mkfifo函數(shù)調(diào)用。

               
          5. 信號(Signal):

                信號是軟件中斷,在Linux下面用戶可以通過kill命令給某個進程發(fā)送一個特定的信號,也可以通過鍵盤發(fā)送一些信號,比如CTRL+C可能觸發(fā) CGIINT信號,而CTRL+\可能觸發(fā)SGIQUIT信號等,除此之外,內(nèi)核在某些情況下也會給進程發(fā)送信號,比如在訪問內(nèi)存越界時產(chǎn)生 SGISEGV信號,當(dāng)然,進程本身也可以通過kill,raise等函數(shù)給自己發(fā)送信號。對于Linux下支持的信號類型,大家可以通過"man 7 signal"或者"kill -l"查看到相關(guān)列表和說明。

                對于有些信號,進程會有默認的響應(yīng)動作,而有些信號,進程可能直接會忽略,當(dāng)然,用戶還可以對某些信號設(shè)定專門的處理函數(shù)。在shell程序中,我們可以 通過trap命令(shell的內(nèi)置命令)來設(shè)定響應(yīng)某個信號的動作(某個命令或者是你定義的某個函數(shù)),而在C語言里頭可以通過signal調(diào)用注冊某 個信號的處理函數(shù)。這里僅僅演示trap命令的用法。

            Quote:

            $ function signal_handler {    #定一個signal_handler的函數(shù),>是按下?lián)Q行符號自動出現(xiàn)的
            > echo "hello, world"
            > }
            $ trap signal_handle SIGINT    #執(zhí)行該命令設(shè)定:當(dāng)發(fā)生SIGINT信號時將打印hello。
            $ hello, world            #按下CTRL+C,可以看到屏幕上輸出了hello, world字符串



                類似地,如果設(shè)定信號0的響應(yīng)動作,那么就可以用trap來模擬C語言程序中的atexit程序終止函數(shù)的登記,即通過trap signal_handler SIGQUIT設(shè)定的signal_handler函數(shù)將在程序退出的時候被執(zhí)行。信號0是一個特別的信號,在POSIX.1中把信號編號0定義為空信 號,這將常被用來確定一個特定進程是否仍舊存在。當(dāng)一個程序退出時會觸發(fā)該信號。

            Quote:

            $ cat sigexit.sh
            #!/bin/bash

            function signal_handler {
                    echo "hello, world"
            }
            trap signal_handler 0
            $ chmod +x sigexit.sh
            $ ./sigexit.sh    #實際上在shell編程時,會用這種方式在程序退出時來做一些清理臨時文件的收尾工作
            hello, world

              

            7、作業(yè)和作業(yè)控制

                當(dāng)我們?yōu)橥瓿梢恍?fù)雜的任務(wù)而將多個命令通過|,>,<, ;, (, )等組合在一起的時候,通常這樣個命令序列會啟動多個進程,它們之間通過管道等進行通信。而有些時候,我們在執(zhí)行一個任務(wù)的同時,還有其他的任務(wù)需要處 理,那么就經(jīng)常會在命令序列的最后加上一個&,或者在執(zhí)行命令以后,按下CTRL+Z讓前一個命令暫停。以便做其他的任務(wù)。等做完其他一些任務(wù)以 后,再通過fg命令把后臺的任務(wù)切換到前臺。這樣一種控制過程通常被成為作業(yè)控制,而那些命令序列則被成為作業(yè),這個作業(yè)可能涉及一個或者多個程序,一個 或者多個進程。下面演示一下幾個常用的作業(yè)控制操作。

            Quote:

            $ sleep 50 &      #讓程序在后臺運行,將打印[作業(yè)號]和進程號
            [1] 11137
            $ fg %1            #使用shell內(nèi)置命令fg把作業(yè)1調(diào)到前臺運行,然后按下CTRL+Z讓該進程暫停
            sleep 50

            [1]+  Stopped                 sleep 50
            $ jobs            #查看當(dāng)前作業(yè)情況,有一個作業(yè)停止
            [1]+  Stopped                 sleep 50
            $ sleep 100 &       #讓另外一個作業(yè)在后臺運行
            [2] 11138        
            $ jobs            #查看當(dāng)前作業(yè)情況,一個正在運行,一個停止
            [1]+  Stopped                 sleep 50
            [2]-  Running                 sleep 100 &
            $ bg %1            #啟動停止的進程并讓它在后臺運行
            [2]+ sleep 50 &



                不過,要在命令行下使用作業(yè)控制,需要當(dāng)前shell,內(nèi)核終端驅(qū)動等對作業(yè)控制支持才行。

            參考資料

            <UNIX環(huán)境高級編程>相關(guān)章節(jié)

          6. posted on 2008-03-14 15:34 隨意門 閱讀(1018) 評論(0)  編輯 收藏 引用


            只有注冊用戶登錄后才能發(fā)表評論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


            久久无码AV中文出轨人妻| 亚洲精品国产第一综合99久久| 思思久久99热免费精品6| 久久久久久午夜精品| 久久久亚洲AV波多野结衣| 人妻精品久久无码区| 国产亚洲精久久久久久无码| 久久91综合国产91久久精品| 久久艹国产| 99蜜桃臀久久久欧美精品网站| 久久精品成人免费看| 久久综合色区| 久久电影网一区| 综合久久给合久久狠狠狠97色| 国产精品成人久久久久三级午夜电影| 久久精品国产亚洲AV蜜臀色欲 | 欧美精品一区二区精品久久 | 无码任你躁久久久久久老妇App| 99久久久精品免费观看国产 | 亚洲中文字幕久久精品无码APP| 91久久精品无码一区二区毛片| 久久久老熟女一区二区三区| 久久频这里精品99香蕉久| 色综合久久综合网观看| 久久久久亚洲av无码专区导航| 久久亚洲熟女cc98cm| 亚洲精品NV久久久久久久久久| 91精品久久久久久无码| 久久91精品久久91综合| jizzjizz国产精品久久| 久久夜色精品国产噜噜亚洲AV| 免费无码国产欧美久久18| 久久国产亚洲精品| 欧美激情一区二区久久久| 久久久久亚洲av成人网人人软件| 日韩电影久久久被窝网| 婷婷久久综合九色综合绿巨人 | 97精品国产97久久久久久免费| 久久国产精品一区二区| 国产成人综合久久综合| 久久无码精品一区二区三区|