shell調試手段三則

shell調試手段三則

1. time

用途說明

time命令常用於測量一個命令的運行時間,注意不是用來顯示和修改系統時間的(這是date命令乾的事情)。

常用參數


time命令最常用的使用方式就是在其後面直接跟上命令和參數:


time <command> [<arguments...>]


在命令執行完成之後就會打印出CPU的使用情況

    real    0m5.064s     <== 實際使用時間(real time)
    user    0m0.020s     <== 用戶態使用時間(the process spent in user mode)
    sys     0m0.040s     <== 內核態使用時間(the process spent in kernel mode)
    time命令跟上-p參數可以只打印時間數值(秒數),不打印單位。


使用示例

使用示例
示例一 統計運行時間::

    [root@web186 root]# time find . -name "mysql.sh"
    ./work186/sms/bin/mysql.sh
    ./work186/sms/src/scripts/mysql.sh


    real    0m14.837s
    user    0m0.030s
    sys     0m0.120s
    [root@web186 root]#
注: **real遠大於user加上sys,因爲find需要遍歷各個目錄,需要大量的I/O操作,
而磁盤I/O通常是最慢的環節,因此大部分時間find進程都在等待磁盤I/O完成。**


其實系統中有兩個time

    [root@web186 root]# type -a time
    time is a shell keyword
    time is /usr/bin/time

注:通過這條命令我們可以發現我們常用的time其實是一個Shell關鍵字,
還有一個外部命令/usr/bin/time,它有何不同呢?::
    [root@web186 root]# /usr/bin/time
    Usage: /usr/bin/time [-apvV] [-f format] [-o file] [--append] [--verbose]
           [--portability] [--format=format] [--output=file] [--version]
                  [--help] command [arg...]

注:外部命令/usr/bin/time功能更強大。


解決time命令輸出信息的重定向問題

time命令的輸出信息是打印在標準錯誤輸出上的, 我們通過一個簡單的嘗試來驗證一下。::
    [root@web186 root]# time find . -name "mysql.sh" >1.txt


    real    0m0.081s
    user    0m0.060s
    sys     0m0.020s

*通過上面的嘗試,發現無法將time的輸出信息重定向到文件裏面,爲什麼?
因爲time是shell的關鍵字,shell做了特殊處理,它會把time命令後面的命令行作爲一個
整體來進行處理,在重定向時,實際上是針對後面的命令來的,
time命令本身的輸出並不會被重定向的。那現在怎麼辦呢?*


第一種解決方法,就是將time命令和將要執行的命令行放到一個shell代碼塊中,
也就是一對大括號中,要注意空格和分號的使用。::
    [root@web186 root]# { time find . -name "mysql.sh"; } 2>2.txt 
    ./work186/sms/bin/mysql.sh
    ./work186/sms/src/scripts/mysql.sh
    [root@web186 root]# cat 2.txt 


    real    0m0.068s
    user    0m0.030s
    sys     0m0.040s
另外一種方式就是使用子Shell的方式,如下所示::
    [root@web186 root]# (time find . -name "mysql.sh") 2>2.txt 
    ./work186/sms/bin/mysql.sh
    ./work186/sms/src/scripts/mysql.sh
    [root@web186 root]# cat 2.txt 


    real    0m0.083s
    user    0m0.040s
    sys     0m0.020s
    [root@web186 root]#

2. lsof

lsof是遵從Unix哲學的典範,它只做一件事情,並且做的相當完美——它可以列出某個進
程打開的所有文件信息。打開的文件可能是普通的文件,目錄,NFS文件,塊文件,
字符文件,共享庫,常規管道,明明管道,符號鏈接,Socket流,網絡Socket,
UNIX域Socket,以及其它更多。因爲Unix系統中幾乎所有東西都是文件,你可以想象lsof該有多有用。


找出誰在使用某個文件

    # lsof /path/to/file

只需要執行文件的路徑,lsof就會列出所有使用這個文件的進程,你也可以列出多個文件,lsof會列出所有使用這些文件的進程。


遞歸查找某個目錄中所有打開的文件

    # lsof +D /usr/lib
加上+D參數,lsof會對指定目錄進行遞歸查找,注意這個參數要比grep版本慢::
   # lsof | grep '/usr/lib'
之所以慢是因爲+D首先查找所有的文件,然後一次性輸出。

列出某個用戶打開的所有文件

    # lsof -u rms,root
這條命令會列出所有rms和root用戶打開的文件。


查找某個程序打開的所有文件

    # lsof -c apache

-c選項限定只列出以apache開頭的進程打開的文件:


列出所有由某個PID對應的進程打開的文件

    # lsof -p 450,980,333

-p選項讓你可以使用進程id來過濾輸出。


列出所有網絡連接

    # lsof -i

lsof的-i選項可以列出所有打開了網絡套接字(TCP和UDP)的進程。


列出所有TCP網絡連接

    # lsof -i tcp

也可以爲-i選項加上參數,比如tcp,tcp選項會強制lsof只列出打開TCP sockets的進程。


找到使用某個端口的進程

    # lsof -i :25

:25和-i選項組合可以讓lsof列出佔用TCP或UDP的25端口的進程。


你也可以使用/etc/services中制定的端口名稱來代替端口號,比如

    # lsof -i :smtp

找到使用某個udp端口號的進程::


    # lsof -i udp:53


3. strace

    [root@localhost ~]# ps -ef|grep rb; netstat -anp | grep rb
    root      1613     1  0 13:36 ?        00:00:00 ./rbtunnel [email protected] 1028
    root      4809  4720  0 14:21 pts/3    00:00:00 grep rb
    root     13236     1  0 Dec10 ?        00:00:00 ./rbserver
    ...
    tcp        0      0 0.0.0.0:13651               0.0.0.0:*                   LISTEN      13236/./rbserver    
    tcp       20      0 124.232.156.156:15056       114.255.102.198:57256       CLOSE_WAIT  1613/./rbtunnel     
    tcp   136458      0 124.232.156.156:15057       221.219.116.77:1182         ESTABLISHED 1613/./rbtunnel     
    tcp     1117  26064 124.232.156.156:15056       114.255.102.198:57667       ESTABLISHED 1613/./rbtunnel     

發現進程1613的數據轉發有問題,使用strace來看一下。
    [root@localhost ~]# strace -p 1613
    Process 1613 attached - interrupt to quit
    gettimeofday({1355293347, 691650}, NULL) = 0
    write(3, "I 0 14:20:25.792080 action.tcp_r"..., 97) = 97
    select(10, [4 6 8 9], NULL, NULL, {30, 0}) = 3 (in [4 8 9], left {30, 0})
    recv(9, "\36\3\317\324\n_\305\344\1\236|\317\31\\\361\r`\310U5*\266\2155\320R\3158\347\342\307\310"..., 4095, 0) = 4095
    gettimeofday({1355293347, 713394}, NULL) = 0
    send(8, "\36\3\317\324\n_\305\344\1\236|\317\31\\\361\r`\310U5*\266\2155\320R\3158\347\342\307\310"..., 4095, 0
    Ctrl+C
    <unfinished ...>
    Process 1613 detached
    [root@localhost ~]# )



參考資料:

Linux命令之time - 測定一個命令的資源使用情況
Unix調試的瑞士軍刀:lsof 
使用strace找出程序在哪個地方吊死
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章