一文读懂Shell进程操作:编程新手必看_ci

什么是程序,什么又是进程

程序是指令的集合,而进程则是程序执行的基本单元。为了让程序完成它的工作,必须让程序运行起来成为进程,进而利用处理器资源、内存资源,进行各种 I/O 操作,从而完成某项特定工作。

从这个意思上说,程序是静态的,而进程则是动态的。

进程有区别于程序的地方还有:进程除了包含程序文件中的指令数据以外,还需要在内核中有一个数据结构用以存放特定进程的相关属性,以便内核更好地管理和调度进程,从而完成多进程协作的任务。因此,从这个意义上可以说“高于”程序,超出了程序指令本身。

如果进行过多进程程序的开发,又会发现,一个程序可能创建多个进程,通过多个进程的交互完成任务。在 Linux 下,多进程的创建通常是通过 fork 系统调用来实现。从这个意义上来说程序则”包含”了进程。

另外一个需要明确的是,程序可以由多种不同程序语言描述,包括 C 语言程序、汇编语言程序和最后编译产生的机器指令等。

下面简单讨论 Linux 下面如何通过 Shell 进行进程的相关操作。


进程的创建

通常在命令行键入某个程序文件名以后,一个进程就被创建了。例如,


范例:让程序在后台运行

$ sleep 100 &
[1] 9298


范例:查看进程 ID

pidof可以查看指定程序名的进程ID:

$ pidof sleep
9298


范例:查看进程的内存映像

$ cat /proc/9298/maps
08048000-0804b000 r-xp 00000000 08:01 977399     /bin/sleep
0804b000-0804c000 rw-p 00003000 08:01 977399     /bin/sleep
0804c000-0806d000 rw-p 0804c000 00:00 0          [heap]
b7c8b000-b7cca000 r--p 00000000 08:01 443354
...
bfbd8000-bfbed000 rw-p bfbd8000 00:00 0          [stack]
ffffe000-fffff000 r-xp 00000000 00:00 0          [vdso]

程序被执行后,就被加载到内存中,成为了一个进程。上面显示了该进程的内存映像(虚拟内存),包括程序指令、数据,以及一些用于存放程序命令行参数、环境变量的栈空间,用于动态内存申请的堆空间都被分配好。

关于程序在命令行执行过程的细节,请参考《Linux 命令行下程序执行的一刹那》

实际上,创建一个进程,也就是说让程序运行,还有其他的办法,比如,通过一些配置让系统启动时自动启动程序(具体参考 man init),或者是通过配置 crond (或者 at)让它定时启动程序。除此之外,还有一个方式,那就是编写 Shell 脚本,把程序写入一个脚本文件,当执行脚本文件时,文件中的程序将被执行而成为进程。这些方式的细节就不介绍,下面了解如何查看进程的属性。

需要补充一点的是:在命令行下执行程序,可以通过 ulimit 内置命令来设置进程可以利用的资源,比如进程可以打开的最大文件描述符个数,最大的栈空间,虚拟内存空间等。具体用法见 help ulimit 。


查看进程的属性和状态

可以通过 ps 命令查看进程相关属性和状态,这些信息包括进程所属用户,进程对应的程序,进程对 cpu 和内存的使用情况等信息。熟悉如何查看它们有助于进行相关的统计分析等操作。


范例:通过 ps 命令查看进程属性

查看系统当前所有进程的属性:

$ ps -ef

查看命令中包含某字符的程序对应的进程,进程 ID 是 1 。 TTY 为?表示和终端没有关联:

$ ps -C init
  PID TTY          TIME CMD
    1 ?        00:00:01 init

选择某个特定用户启动的进程:

$ ps -U falcon

按照指定格式输出指定内容,下面输出命令名和 cpu 使用率:

$ ps -e -o "%C %c"

打印 cpu 使用率最高的前 4 个程序:

$ ps -e -o "%C %c" | sort -u -k1 -r | head -5
 7.5 firefox-bin
 1.1 Xorg
 0.8 scim-panel-gtk
 0.2 scim-bridge

获取使用虚拟内存最大的 5 个进程:

$ ps -e -o "%z %c" | sort -n -k1 -r | head -5
349588 firefox-bin
 96612 xfce4-terminal
 88840 xfdesktop
 76332 gedit
 58920 scim-panel-gtk


范例:通过 pstree 查看进程亲缘关系

系统所有进程之间都有“亲缘”关系,可以通过 pstree 查看这种关系:

$ pstree

上面会打印系统进程调用树,可以非常清楚地看到当前系统中所有活动进程之间的调用关系。


范例:用top动态查看进程信息

$ top

该命令最大特点是可以动态地查看进程信息,当然,它还提供了一些其他的参数,比如 -S 可以按照累计执行时间的大小排序查看,也可以通过 -u 查看指定用户启动的进程等。

补充: top 命令支持交互式,比如它支持 u 命令显示用户的所有进程,支持通过 k 命令杀掉某个进程;如果使用 -n 1 选项可以启用批处理模式,具体用法为:

$ top -n 1 -b


范例:确保特定程序只有一个副本在运行

下面来讨论一个有趣的问题:如何让一个程序在同一时间只有一个在运行。

这意味着当一个程序正在被执行时,它将不能再被启动。那该怎么做呢?

假如一份相同的程序被复制成了很多份,并且具有不同的文件名被放在不同的位置,这个将比较糟糕,所以考虑最简单的情况,那就是这份程序在整个系统上是唯一的,而且名字也是唯一的。这样的话,有哪些办法来回答上面的问题呢?

总的机理是:在程序开头检查自己有没有执行,如果执行了则停止否则继续执行后续代码。

策略则是多样的,由于前面的假设已经保证程序文件名和代码的唯一性,所以通过 ps 命令找出当前所有进程对应的程序名,逐个与自己的程序名比较,如果已经有,那么说明自己已经运行了。

ps -e -o "%c" | tr -d " " | grep -q ^init$   #查看当前程序是否执行
[ $? -eq 0 ] && exit   #如果在,那么退出, $?表示上一条指令是否执行成功

每次运行时先在指定位置检查是否存在一个保存自己进程 ID 的文件,如果不存在,那么继续执行,如果存在,那么查看该进程 ID 是否正在运行,如果在,那么退出,否则往该文件重新写入新的进程 ID,并继续。

pidfile=/tmp/$0".pid"
if [ -f $pidfile ]; then
       OLDPID=$(cat $pidfile)
    ps -e -o "%p" | tr -d " " | grep -q "^$OLDPID$"
    [ $? -eq 0 ] && exit
fi

echo $$ > $pidfile

#... 代码主体

#设置信号0的动作,当程序退出时触发该信号从而删除掉临时文件
trap "rm $pidfile"      0

更多实现策略自己尽情发挥吧!


调整进程的优先级

在保证每个进程都能够顺利执行外,为了让某些任务优先完成,那么系统在进行进程调度时就会采用一定的调度办法,比如常见的有按照优先级的时间片轮转的调度算法。这种情况下,可以通过 renice 调整正在运行的程序的优先级,例如:`


范例:获取进程优先级

$ ps -e -o "%p %c %n" | grep xfs
 5089 xfs               0


范例:调整进程的优先级

$ renice 1 -p 5089
renice: 5089: setpriority: Operation not permitted
$ sudo renice 1 -p 5089   #需要权限才行
[sudo] password for falcon:
5089: old priority 0, new priority 1
$ ps -e -o "%p %c %n" | grep xfs  #再看看,优先级已经被调整过来了
 5089 xfs               1


结束进程

既然可以通过命令行执行程序,创建进程,那么也有办法结束它。可以通过 kill 命令给用户自己启动的进程发送某个信号让进程终止,当然“万能”的 root 几乎可以 kill 所有进程(除了 init 之外)。例如,


范例:结束进程

$ sleep 50 &   #启动一个进程
[1] 11347
$ kill 11347

kill 命令默认会发送终止信号( SIGTERM )给程序,让程序退出,但是 kill 还可以发送其他信号,这些信号的定义可以通过 man 7 signal 查看到,也可以通过 kill -l 列出来。

$ man 7 signal
$ kill -l
 1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL
 5) SIGTRAP      6) SIGABRT      7) SIGBUS       8) SIGFPE
 9) SIGKILL     10) SIGUSR1     11) SIGSEGV     12) SIGUSR2
13) SIGPIPE     14) SIGALRM     15) SIGTERM     16) SIGSTKFLT
17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP
21) SIGTTIN     22) SIGTTOU     23) SIGURG      24) SIGXCPU
25) SIGXFSZ     26) SIGVTALRM   27) SIGPROF     28) SIGWINCH
29) SIGIO       30) SIGPWR      31) SIGSYS      34) SIGRTMIN
35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3  38) SIGRTMIN+4
39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12
47) SIGRTMIN+13 48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14
51) SIGRTMAX-13 52) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10
55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7  58) SIGRTMAX-6
59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
63) SIGRTMAX-1  64) SIGRTMAX
阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: shell