procref1.html
来自「BASH Shell 编程 经典教程 《高级SHELL脚本编程》中文版」· HTML 代码 · 共 687 行
HTML
687 行
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><HTML><HEAD><TITLE>/proc</TITLE><METANAME="GENERATOR"CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINKREL="HOME"TITLE="高级Bash脚本编程指南"HREF="index.html"><LINKREL="UP"TITLE="/dev和/proc"HREF="devproc.html"><LINKREL="PREVIOUS"TITLE="/dev"HREF="devref1.html"><LINKREL="NEXT"TITLE="Zero与Null"HREF="zeros.html"></HEAD><BODYCLASS="SECT1"BGCOLOR="#FFFFFF"TEXT="#000000"LINK="#0000FF"VLINK="#840084"ALINK="#0000FF"><DIVCLASS="NAVHEADER"><TABLESUMMARY="Header navigation table"WIDTH="100%"BORDER="0"CELLPADDING="0"CELLSPACING="0"><TR><THCOLSPAN="3"ALIGN="center">高级Bash脚本编程指南: 一本深入学习shell脚本艺术的书籍</TH></TR><TR><TDWIDTH="10%"ALIGN="left"VALIGN="bottom"><AHREF="devref1.html"ACCESSKEY="P">前一页</A></TD><TDWIDTH="80%"ALIGN="center"VALIGN="bottom">27. /dev和/proc</TD><TDWIDTH="10%"ALIGN="right"VALIGN="bottom"><AHREF="zeros.html"ACCESSKEY="N">下一页</A></TD></TR></TABLE><HRALIGN="LEFT"WIDTH="100%"></DIV><DIVCLASS="SECT1"><H1CLASS="SECT1"><ANAME="PROCREF1">27.2. <TTCLASS="FILENAME">/proc</TT></A></H1><P><TTCLASS="FILENAME">/proc</TT>目录实际上是一个伪文件系统. <TTCLASS="FILENAME">/proc</TT>目录中的文件用来映射当前运行的系统, 内核<EM>进程</EM>以及与它们相关的状态与统计信息. </P><P> <TABLEBORDER="1"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="SCREEN"><SAMPCLASS="PROMPT">bash$ </SAMP><KBDCLASS="USERINPUT">cat /proc/devices</KBD><SAMPCLASS="COMPUTEROUTPUT">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</SAMP><SAMPCLASS="PROMPT">bash$ </SAMP><KBDCLASS="USERINPUT">cat /proc/interrupts</KBD><SAMPCLASS="COMPUTEROUTPUT"> 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</SAMP><SAMPCLASS="PROMPT">bash$ </SAMP><KBDCLASS="USERINPUT">cat /proc/partitions</KBD><SAMPCLASS="COMPUTEROUTPUT">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 ...</SAMP><SAMPCLASS="PROMPT">bash$ </SAMP><KBDCLASS="USERINPUT">cat /proc/loadavg</KBD><SAMPCLASS="COMPUTEROUTPUT">0.13 0.42 0.27 2/44 1119</SAMP><SAMPCLASS="PROMPT">bash$ </SAMP><KBDCLASS="USERINPUT">cat /proc/apm</KBD><SAMPCLASS="COMPUTEROUTPUT">1.16 1.2 0x03 0x01 0xff 0x80 -1% -1 ?</SAMP> </PRE></FONT></TD></TR></TABLE> </P><P>Shell脚本可以从<TTCLASS="FILENAME">/proc</TT>目录下的某些特定文件中提取数据. <ANAME="AEN14936"HREF="#FTN.AEN14936"><SPANCLASS="footnote">[1]</SPAN></A></P><P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 FS=iso # 内核是否支持ISO文件系统? 2 3 grep $FS /proc/filesystems # iso9660</PRE></FONT></TD></TR></TABLE></P><P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 kernel_version=$( awk '{ print $3 }' /proc/version )</PRE></FONT></TD></TR></TABLE></P><P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 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</PRE></FONT></TD></TR></TABLE></P><P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 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</PRE></FONT></TD></TR></TABLE></P><P><TTCLASS="FILENAME">/proc</TT>目录下包含有许多以不同数字命名的子目录. 这些作为子目录名字的数字, 代表的是当前正在运行进程的<AHREF="internalvariables.html#PPIDREF">进程ID</A>. 在这些以数字命名的子目录中, 每一个子目录都有许多文件用来保存对应进程的可用信息. 文件<TTCLASS="FILENAME">stat</TT>和<TTCLASS="FILENAME">status</TT>保存着进程运行时的各项统计信息, 文件<TTCLASS="FILENAME">cmdline</TT>保存着进程被调用时的命令行参数, 而文件<TTCLASS="FILENAME">exe</TT>是一个符号链接, 这个符号链接指向这个运行进程的完整路径. 还有许多类似这样的文件, 如果从脚本的视角来看它们的话, 这些文件都非常的有意思. </P><DIVCLASS="EXAMPLE"><HR><ANAME="PIDID"></A><P><B>例子 27-2. 找出与给定PID相关联的进程</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 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 # Error message >stderr(错误信息重定向到标准错误). 14 exit $E_WRONGARGS 15 fi 16 17 pidno=$( ps ax | grep $1 | awk '{ print $1 }' | grep $1 ) 18 # 从"ps"命令的输出中搜索带有pid的行, pid位置在第一列#1, 由awk过滤出来. 19 # 然后再次确认这就是我们所要找的进程, 而不是由这个脚本调用所产生的进程. 20 # 最后的"grep $1"就是用来过滤掉这种可能性. 21 # 22 # pidno=$( ps ax | awk '{ print $1 }' | grep $1 ) 23 # 这么写就可以了, 这一点由Teemu Huovila指出. 24 25 if [ -z "$pidno" ] # 如果经过所有的过滤之后, 得到的结果是一个长度为0的字符串, 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'不是一个信号, but 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</PRE></FONT></TD></TR></TABLE><HR></DIV><DIVCLASS="EXAMPLE"><HR><ANAME="CONSTAT"></A><P><B>例子 27-3. 网络连接状态</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 3 PROCNAME=pppd # ppp守护进程 4 PROCFILENAME=status # 在这里寻找信息. 5 NOTCONNECTED=65 6 INTERVAL=2 # 每2秒刷新一次. 7 8 pidno=$( ps ax | grep -v "ps ax" | grep -v grep | grep $PROCNAME | awk '{ print $1 }' ) 9 # 找出'pppd'所对应的进程号, 即'ppp守护进程'. 10 # 必须过滤掉由搜索本身所产生的进程行. 11 # 12 # 然而, 就像Oleg Philon所指出的那样, 13 #+ 如果使用"pidof"的话, 就会非常简单. 14 # pidno=$( pidof $PROCNAME ) 15 # 16 # 从经验中总结出来的忠告: 17 #+ 当命令序列变得非常复杂的时候, 一定要找到更简洁的方法. 18 19 20 if [ -z "$pidno" ] # 如果没有找到匹配的pid, 那么就说明相应的进程没运行. 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 # 提高这个脚本的用户友好性. </PRE></FONT></TD></TR></TABLE><HR></DIV><DIVCLASS="WARNING"><P></P><TABLECLASS="WARNING"WIDTH="100%"BORDER="0"><TR><TDWIDTH="25"ALIGN="CENTER"VALIGN="TOP"><IMGSRC="./images/warning.gif"HSPACE="5"ALT="Warning"></TD><TDALIGN="LEFT"VALIGN="TOP"><P>一般来说, 在<TTCLASS="FILENAME">/proc</TT>目录中, 进行<EM>写</EM>文件操作是非常危险的, 因为这么做可能会破坏文件系统, 甚至于摧毁整个机器. </P></TD></TR></TABLE></DIV></DIV><H3CLASS="FOOTNOTES">注意事项</H3><TABLEBORDER="0"CLASS="FOOTNOTES"WIDTH="100%"><TR><TDALIGN="LEFT"VALIGN="TOP"WIDTH="5%"><ANAME="FTN.AEN14936"HREF="procref1.html#AEN14936"><SPANCLASS="footnote">[1]</SPAN></A></TD><TDALIGN="LEFT"VALIGN="TOP"WIDTH="95%"><P>某些系统命令也可做类似的事情, 比如<AHREF="system.html#PROCINFOREF">procinfo</A>, <AHREF="system.html#FREEREF">free</A>, <AHREF="system.html#VMSTATREF">vmstat</A>, <AHREF="system.html#LSDEVREF">lsdev</A>, 和<AHREF="system.html#UPTIMEREF">uptime</A>. </P></TD></TR></TABLE><DIVCLASS="NAVFOOTER"><HRALIGN="LEFT"WIDTH="100%"><TABLESUMMARY="Footer navigation table"WIDTH="100%"BORDER="0"CELLPADDING="0"CELLSPACING="0"><TR><TDWIDTH="33%"ALIGN="left"VALIGN="top"><AHREF="devref1.html"ACCESSKEY="P">前一页</A></TD><TDWIDTH="34%"ALIGN="center"VALIGN="top"><AHREF="index.html"ACCESSKEY="H">首页</A></TD><TDWIDTH="33%"ALIGN="right"VALIGN="top"><AHREF="zeros.html"ACCESSKEY="N">下一页</A></TD></TR><TR><TDWIDTH="33%"ALIGN="left"VALIGN="top"><TTCLASS="FILENAME">/dev</TT></TD><TDWIDTH="34%"ALIGN="center"VALIGN="top"><AHREF="devproc.html"ACCESSKEY="U">上一级</A></TD><TDWIDTH="33%"ALIGN="right"VALIGN="top">Zero与Null</TD></TR></TABLE></DIV></BODY></HTML>
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?