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找出程序在哪個地方吊死