Shell 与进程 gaunthan Posted on May 14 2016 ? Linux Shell ? ## 概述 操作系统的一个主要任务就是从用户、服务与应用程序的角度运行进程。这些进程由内核中的一个进程进行跟踪。进程表包含了系统中每个进程的当前状态,并且系统调度器决定每个进程何时分配到一个CPU,以及何时与CPU分离。 ps命令可以查询进程表,并有一组开关用来调整从整个进程树中显示哪些信息。此外,利用/proc虚拟文件系统能进一步窥视正在运行的内核。进程表中的每个进程在/proc下都有一个目录。从进程的目录中可以找到进程的状态:当前目录与打开的文件。/proc包含了直接读写内核状态的机制,包括网络设置、内存选项、硬件信息,甚至可以强制机器崩溃。 ## ps命令 ps命令有很多的选项,其中比较常用的`-f`选项将以**全格式**输出信息:  其中各个字段的解释见下表: |字段|含义| |--| |UID|用户名| |PID|进程ID| |PPID|父进程ID| |C|进程消耗CPU时间的粗略百分比| |STIME|进程开始时间| |TTY|关联的终端| |TIME|进程使用的CPU时间| |CMD|可执行文件的全称| 可以在命令行中使用很多ps选项: * 显示与某个虚拟终端相关联的进程 使用`-t`选项指定虚拟终端。如 ``` #显示与第0个虚拟终端相关联的进程 ps -ft /dev/pts/0 ``` * 显示某个用户拥有的进程 使用`-u`指定用户。如 ``` #显示用户han拥有的进程 ps -fu han ``` 使用`-F`标志可以给出关于进程的更多细节。相比于`-f`选项,增加了以下几个字段: |字段|含义| |--| |SZ|表示整个进程的页数目(在x86中通常是4KB)| |RSS|表示进程占用的全部物理内存,但不包括交换数据| |PSR|表示进程运行所在的CPU的ID| ### ps显示的行宽 ps会将输出的长度限制在终端的宽度以内。当写入对象不是终端(tty)时,则不会限制输出的宽度,而是会显示整个命令行。因此,可以将ps的输出通过管道定向到`cat -`中。它使得ps本身运行在管道中。例子如下: ``` ps -fu han | cat - ``` ### 精确分析进程表 在某些情况下,能精确识别目标进程极其重要,如对于自动关闭进程的脚本而言。通常,要查找某个进程,可以运行:  可以看到图中有一个意料之外的结果:`grep vsftpd`也会被匹配出来。通过调用grep命令,进程表已经被改变了。对这种情况的解决方案为: ``` ps -eaf | grep vsftpd | grep -v grep ``` Linux(与现代Unix)具有一套命令集,它们能基于各种准则来识别进程。与对ps的输出执行grep不同,`pgrep`默认只匹配实际的进程名。因为pgrep只返回一个PID列表,所以不会再出现上面的那种情况:  这样,就可以通过命令kill -9 \`pgrep -x vsftpd\`来精确终止进程。 另外,因为pgrep经常用于关闭进程,所以它被符号链接到一个非常相似的命令:`pkill`。pkill的语法与pgrep非常相似,但不仅仅是列出PID,它还会关闭进程。所以上面那条命令还可以通过`pkill -x vsftpd`来实现。 可以让pkill使用某个不同的信号,语法与kill相同: |编号 |信号|作用| |--| |0|0|从shell退出| |1|SIGHUP|清理;重新读取配置文件,然后继续运行| |2|SIGINT|中断| |3|SIGQUIT|退出| |6|SIGABRT|中止| |9|SIGKILL|立即关闭进程| |14|SIGALRM|报警时钟| |15|SIGTERM|清理并终止| **当关闭机器时,OS会正常调用注册过的关闭脚本,并向余下的进程发送SIGTERM信号,最后向仍然在运行的所有进程发送SIGKILL信号。** ## killall killall会关闭匹配给定条件的进程,与pgrep一类的命令非常相似。一些常用的选项有: |选项|含义| |--| |-e|精确匹配| |-u|指定用户ID以对查找进行限制| |-s|指定不同的信号| ### 简单的应用程序启动/关闭脚本 ``` $ cat /etc/init.d/myapp #!/bin/bash case "$1" in #这可能会产生一系列名字和ID未知的进程,但是除非与suid有关,否则它们都将被用户myapp拥有 "start") su - myapp /path/to/program/startall ;; #这条命令将杀死所有属于用户myapp的进程 "stop") killall -u myapp ;; *) echo "Usage: `basename $0` start|stop" ;; esac $ ``` ## /proc虚拟文件系统 内核进程表与其中进程的状态都可以对其PID从/proc虚拟文件系统中得到。另外还有一个特殊的符号链接/proc/self。对于任何引用/proc/self的进程,该链接都会表现为指向运行进程的符号链接:  shell的PID为2294。在ls程序中,/proc/self是它自身的链接,指向/proc/3052,所以在执行这条命令时,ls的PID为3052。 ## I/O重定向 每个进程在创建时都会打开3个标准文件:标准输入(stdin)、标准输出(stdout)和标准错误(stderr),文件描述符分别为0、1和2。通过/proc/self与ls可以很好的理解重定向:  由上图可知ls命令的stdin、stdout与stderr都是终端pts0。可以通过重定向符来修改它们的指向: ``` $ ls -l /proc/self/fd /nosuchfile < /etc/bashrc > output.txt 2> error.txt ``` 分别查看两文件的内容:  可见ls的所有输入和输出都重定向到了其他文件。 ## exec shell内置命令exec调用内部的系统调用exec(手册3)。该命令有两个主要目的: * 将当前运行进程替换为另一进程 shell本身将被另一个程序替换,这个程序可能是另一个shell或任何其他程序。当用exec调用的程序结束后,控制不会返回到调用shell。 * 调用exec可以用来以副作用的形式实现重定向 ## 管道 管道是Unix与Linux shell的重要特性。管道将两个进程连接在一起,通常是将一个进程的标准输出链接到另一个进程的标准输入。管道并没有将第一个命令的输出写到一个文件,然后将该文件作为输入运行的第二个命令。使用管道完全可以省去中间文件。 ## 后台处理 有时让命令在后台运行并立即将控制返回shell会比较有用。如果脚本不依赖于执行命令的结果或状态,则没有必要等待其结束。命令行最后的`&`符号可以实现进程的后台运行。后台进程的PID被赋值给`$!`,然后主脚本或交互式shell继续照常执行。主脚本还可以对后台运行的子进程运行中的活动进行监视。 ### wait命令 可以等待一个、多个甚至全部的后台进程直到它们运行结束。 ### 使用nohup防止进程挂起 当运行一个耗时非常长的后台进程时,最好能保证即使用户登出其会话或因为网络链接断开而退出,作业也不会终止。nohup命令将运行的进程封装起来,保护它不接收其他使其终止的信号。 默认情况下,nohup的输出会写入到nohup.out。然而,如果stderr和stdout都被重定向到别处,则不会创建nohup.out。 ## /proc和/sys的其他特性 ### /proc/version `/proc/verision`是有关内核版本的只读列表,其中包含了如何编译的详细构建信息。它可以比uname更完整、更精确地检测实际内核版本。 ### SysRq PC键盘上有一个很少用的标记为SysRq的按键。其历史可以追溯到大型机系统,但Linux内核用它在常规方法不可能的情况下与内核进行通信。如果启用这一功能,当用户按下按键`Ctrl+Alt+SysRq`与另一个指定内核操作的按键时,则内核会完成一些提供好的最基本任务:同步到文件系统、报告内存使用情况或者重启系统。下表列出了常用的SysRq按键: |按键|作用| |--| |c|使系统崩溃| |m|显示系统内存| |h|显示帮助| |r|将控制台显示模式设置为Raw| |s|同步所有文件系统| |i|向所有进程(除了init)发送KILL信号| |u|卸载所有文件系统| |b|重启机器| |e|向所有进程(除了init)发送TERM信号| 要安全重启一个挂起的系统,可以依次按下这句话的首字母所对应的快捷键:“**Raising Skinny Elephants Is Utterly Boring**”。它会将控制台设置为原始模式,同步文件系统,向所有进程发送TERM信号,卸载所有文件系统,然后重启机器。 SysRq特性在/proc下有两个文件:`/proc/sysrq-trigger`和`/proc/sys/kernel/sysrq`。后者启用或禁用sysrq特性,对于所有用户可读,对于root用户可写。1表示特性被启用,0表示特性被禁用。 另外可以通过向`/proc/sysrq-trigger`写入相应按键来达到在键盘上按下相应按键的效果: ```shell # echo h > /proc/sysrq-trigger #相当于按下Ctrl+Alt+SysRq+h ``` 如果按下了这个按键而没有看到输出的帮助信息,可以查看系统相应的日志文件,如`/var/log/messages`。 ### /proc/meminfo `/proc/meminfo`提供关于当前内存与虚拟内存系统状态的相应详细的信息。 ### /proc/cpuinfo 只读文件`/proc/cpuinfo`显示安装在系统中的处理器的信息。严格来说,它显示的是系统中的物理线程,所以超线程、多核与多处理器系统会列出很多CPU。 ### /sys `/sys`是sysfs的挂载点,而sysfs是 Linux 内核中设计较新的一种虚拟的基于内存的文件系统,它的作用与 proc 有些类似,但除了与 proc 相同的具有查看和设定内核参数功能之外,还有为 Linux 统一设备模型作为管理之用。相比于 proc 文件系统,使用 sysfs 导出内核数据的方式更为统一,并且组织的方式更好,它的设计从 proc 中吸取了很多教训。 ## References - 鸟哥. 鸟哥的 Linux 私房菜, 基础学习篇. 第 3 版 [M]. 人民邮电出版社, 2010. 赏 Wechat Pay Alipay User Datagram Protocol(UDP) Shell 配置文件的读取流程