Advanced Bash-Scripting Guide: An in-depth exploration of the art of shell scripting | ||
---|---|---|
Prev | Chapter 27. /dev and /proc | Next |
/proc目录实际上是一个伪文件系统 . 在 /proc 目录里的文件是当前运行系统和内核进程及它们的相关信息和统计.
bash$ cat /proc/devices Character devices: 1 mem 2 pty 3 ttyp 4 ttyS 5 cua 7 vcs 10 misc 14 sound 29 fb 36 netlink 128 ptm 136 pts 162 raw 254 pcmcia Block devices: 1 ramdisk 2 fd 3 ide0 9 md bash$ cat /proc/interrupts CPU0 0: 84505 XT-PIC timer 1: 3375 XT-PIC keyboard 2: 0 XT-PIC cascade 5: 1 XT-PIC soundblaster 8: 1 XT-PIC rtc 12: 4231 XT-PIC PS/2 Mouse 14: 109373 XT-PIC ide0 NMI: 0 ERR: 0 bash$ cat /proc/partitions major minor #blocks name rio rmerge rsect ruse wio wmerge wsect wuse running use aveq 3 0 3007872 hda 4472 22260 114520 94240 3551 18703 50384 549710 0 111550 644030 3 1 52416 hda1 27 395 844 960 4 2 14 180 0 800 1140 3 2 1 hda2 0 0 0 0 0 0 0 0 0 0 0 3 4 165280 hda4 10 0 20 210 0 0 0 0 0 210 210 ... bash$ cat /proc/loadavg 0.13 0.42 0.27 2/44 1119 bash$ cat /proc/apm 1.16 1.2 0x03 0x01 0xff 0x80 -1% -1 ? |
Shell 脚本可以从/proc目录中的一些文件里提取数据. [1]
1 FS=iso # ISO 文件系统是否被内核支持? 2 3 grep $FS /proc/filesystems # iso9660 |
1 kernel_version=$( awk '{ print $3 }' /proc/version ) |
1 CPU=$( awk '/model name/ {print $4}' < /proc/cpuinfo ) 2 3 if [ $CPU = Pentium ] 4 then 5 run_some_commands 6 ... 7 else 8 run_different_commands 9 ... 10 fi |
1 devfile="/proc/bus/usb/devices" 2 USB1="Spd=12" 3 USB2="Spd=480" 4 5 6 bus_speed=$(grep Spd $devfile | awk '{print $9}') 7 8 if [ "$bus_speed" = "$USB1" ] 9 then 10 echo "USB 1.1 port found." 11 # 这儿开始操作USB 1.1相关的动作. 12 fi |
/proc目录下有许多不相同的数字命名的子目录. 这些子目录的数字名字都映射对应的当前正在运行的进程的进程号(process ID) . 这些子目录里面有许多文件用于保存对应进程的信息。文件 stat 和 status 保存着进程运行时的各项统计, the cmdline文件保存该进程的被调用时的命令行参数, 而and the exe 文件是该运行进程完整路径名的符号链接. 还有其他一些文件,但从脚本的观点来看它们都非常的有意思。
例子 27-2. 搜索与一个PID相关的进程
1 #!/bin/bash 2 # pid-identifier.sh: 给出指定PID的进程的程序全路径. 3 4 ARGNO=1 # 此脚本期望的参数个数. 5 E_WRONGARGS=65 6 E_BADPID=66 7 E_NOSUCHPROCESS=67 8 E_NOPERMISSION=68 9 PROCFILE=exe 10 11 if [ $# -ne $ARGNO ] 12 then 13 echo "Usage: `basename $0` PID-number" >&2 # 帮助信息重定向到标准出错. 14 exit $E_WRONGARGS 15 fi 16 17 pidno=$( ps ax | grep $1 | awk '{ print $1 }' | grep $1 ) 18 # 搜索命令"ps"输出的第一列. 19 # 然后再次确认是真正我们要寻找的进程,而不是这个脚本调用而产生的进程. 20 # 后一个"grep $1"会滤掉这个可能产生的进程. 21 # 22 # pidno=$( ps ax | awk '{ print $1 }' | grep $1 ) 23 # 也可以, 由 Teemu Huovila指出. 24 25 if [ -z "$pidno" ] # 如果过滤完后结果是一个空字符串, 26 then # 没有对应的PID进程在运行. 27 echo "No such process running." 28 exit $E_NOSUCHPROCESS 29 fi 30 31 # 也可以用: 32 # if ! ps $1 > /dev/null 2>&1 33 # then # 没有对应的PID进程在运行. 34 # echo "No such process running." 35 # exit $E_NOSUCHPROCESS 36 # fi 37 38 # 为了简化整个进程,使用"pidof". 39 40 41 if [ ! -r "/proc/$1/$PROCFILE" ] # 检查读权限. 42 then 43 echo "Process $1 running, but..." 44 echo "Can't get read permission on /proc/$1/$PROCFILE." 45 exit $E_NOPERMISSION # 普通用户不能存取/proc目录的某些文件. 46 fi 47 48 # 最后两个测试可以用下面的代替: 49 # if ! kill -0 $1 > /dev/null 2>&1 # '0'不是一个信号, 50 # 但这样可以测试是否可以 51 # 向该进程发送信号. 52 # then echo "PID doesn't exist or you're not its owner" >&2 53 # exit $E_BADPID 54 # fi 55 56 57 58 exe_file=$( ls -l /proc/$1 | grep "exe" | awk '{ print $11 }' ) 59 # 或 exe_file=$( ls -l /proc/$1/exe | awk '{print $11}' ) 60 # 61 # /proc/pid-number/exe 是进程程序全路径的符号链接。 62 # 63 64 if [ -e "$exe_file" ] # 如果 /proc/pid-number/exe 存在 ... 65 then # 则相应的进程存在. 66 echo "Process #$1 invoked by $exe_file." 67 else 68 echo "No such process running." 69 fi 70 71 72 # 这个被详细讲解的脚本几乎可以用下面的命令代替: 73 # ps ax | grep $1 | awk '{ print $5 }' 74 # 然而, 这样并不会工作... 75 # 因为'ps'输出的第5列是进程的argv[0](即命令行第一个参数,调用时程序用的程序路径本身), 76 # 但不是可执行文件. 77 # 78 # 然而, 下面的两个都可以工作. 79 # find /proc/$1/exe -printf '%l\n' 80 # lsof -aFn -p $1 -d txt | sed -ne 's/^n//p' 81 82 # 由Stephane Chazelas附加注释. 83 84 exit 0 |
例子 27-3. 网络连接状态
1 #!/bin/bash 2 3 PROCNAME=pppd # ppp 守护进程 4 PROCFILENAME=status # 在这儿寻找信息. 5 NOTCONNECTED=65 6 INTERVAL=2 # 两秒刷新一次. 7 8 pidno=$( ps ax | grep -v "ps ax" | grep -v grep | grep $PROCNAME | awk '{ print $1 }' ) 9 # 搜索ppp守护进程'pppd'的进程号. 10 # 一定要过滤掉由搜索进程产生的该行进程. 11 # 12 # 正如Oleg Philon指出的那样, 13 #+ 使用"pidof"命令会相当的简单. 14 # pidno=$( pidof $PROCNAME ) 15 # 16 # 颇有良心的建议: 17 #+ 当命令序列变得复杂的时候,去寻找更简洁的办法。 . 18 19 20 if [ -z "$pidno" ] # 如果没有找到此进程号,则进程没有运行. 21 then 22 echo "Not connected." 23 exit $NOTCONNECTED 24 else 25 echo "Connected."; echo 26 fi 27 28 while [ true ] # 死循环,这儿可以有所改进. 29 do 30 31 if [ ! -e "/proc/$pidno/$PROCFILENAME" ] 32 # 进程运行时,对应的"status"文件会存在. 33 then 34 echo "Disconnected." 35 exit $NOTCONNECTED 36 fi 37 38 netstat -s | grep "packets received" # 取得一些连接统计. 39 netstat -s | grep "packets delivered" 40 41 42 sleep $INTERVAL 43 echo; echo 44 45 done 46 47 exit 0 48 49 # 当要停止它时,可以用Control-C终止. 50 51 # 练习: 52 # --------- 53 # 改进这个脚本,使它能按"q"键退出. 54 # 给脚本更友好的界面. |
一般来说, 写/proc目录里的文件是危险 ,因为这样会破坏这个文件系统或摧毁机器. |
[1] | 一些系统命令, 例如 procinfo, free, vmstat, lsdev, 和uptime 也能做类似 的事情. |