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 lijuanping@itcchina.com 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找出程序在哪个地方吊死
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值