信号和作业控制

作者:jicanmeng

时间:2016年05月18日


  1. 信号
  2. 以后台模式运行脚本
  3. 作业控制
  4. 定时运行作业

1. 信号

linux通过信号来在运行在系统上的进程之间通信。

Ctrl+C组合键会生成SIGINT信号。Ctrl+Z组合键会生成一个SIGTSTP信号,暂停shell中正在运行的进程。当你用Ctrl+Z组合键时,shell会通知你进程被暂停了。

[jicanmeng@andy tmp]$ ./a.sh
                    ^Z
                    [1]+  Stopped              ./a.sh
                [jicanmeng@andy tmp]$ 

方括号中的数字是shell分配的作业号。shell将shell中运行的每个进程称为作业,并为每个作业分配一个唯一的作业号。它会给第一个作业分配作业号1,第二个作业号2,依次类推。

2. 以后台模式运行脚本

要在命令行界面以后台模式运行shell脚本,只要在命令后加个&符号就行了。例如:

[jicanmeng@andy tmp]$ cat a.sh
                    #!/bin/bash

                    var=1
                    while [ $var -le 5 ]
                    do
	                    sleep 1
	                    echo "after $var seconds"
	                    var=$[ $var + 1 ]
                    done
                [jicanmeng@andy tmp]$ ./a.sh &
                    [1] 4457
                [jicanmeng@andy tmp]$ after 1 seconds
                after 2 seconds
                after 3 seconds
                after 4 seconds
                after 5 seconds

                [1]+  Done            ./a.sh
                [jicanmeng@andy tmp]$ 

需要注意的是,虽然使用&使得进程在后台运行,但是这个进程仍然使用终端显示器来显示STDOUT和STDERR消息。另外,当后台进程结束时,它会在终端上显示一条信息,如上面最后的一句。

在终端会话中使用后台进程时,需要特别小心。如果我们使用ps命令,就会看到每个后台进程都绑定到了该终端会话的终端上面了(例如pts/0)。如果进程会话退出了,那么后台进程也会退出。为了解决这个问题,我们可以使用nohup命令。例如:

[jicanmeng@andy tmp]$ cat a.sh
                    #!/bin/bash

                    var=1
                    while [ $var -le 5 ]
                    do
	                    sleep 1
	                    echo "after $var seconds"
	                    var=$[ $var + 1 ]
                    done
                [jicanmeng@andy tmp]$ nohup ./a.sh &
                    [1] 4568
                [jicanmeng@andy tmp]$ nohup: ignoring input and appending output to `nohup.out'
                    [1]+  Done           nohup ./a.sh
                [jicanmeng@andy tmp]$ 

由于nohup命令会从终端解除进程的关联,进程会丢掉到STDOUT和STDERR的连接。为了保存该命令的输出,nohup命令会自动将STDOUT和STDERR的消息重定向到当前目录下的一个名为nohup.out的文件中。

3. 作业控制

[jicanmeng@andy tmp]$ cat a.sh
                    #!/bin/bash

                    var=1
                    while [ $var -le 5 ]
                    do
	                    sleep 1
	                    echo "after $var seconds"
	                    var=$[ $var + 1 ]
                    done
                [jicanmeng@andy tmp]$ ./a.sh
                    ^Z
                    [1]+  Stopped         ./a.sh
                [jicanmeng@andy tmp]$ ./a.sh > a.out &
                    [2] 4655
                [jicanmeng@andy tmp]$ jobs
                    [1]+  Stopped      ./a.sh
                    [2]-  Running      ./a.sh > a.out &
                [jicanmeng@andy tmp]$ 

你可能注意到了jobs命令输出中的加号和减号。带加号的作业会被当做是默认的作业。在使用作业控制命令(如bg或fg)时,如果未在命令行指定任何作业号,该作业会被当作操作对象。带减号的作业则会在当前默认作业完成处理时称为下一个默认作业。任何时候都只有一个带加号的作业和一个带减号的作业,不管shell中有多少个正在运行的作业。

4. 定时运行作业

linux系统提供了两种在预选时间运行脚本的方法:at命令和cron表。

对于at命令,有3个命令需要记住:

要执行 at 时, 必须要有 atd 这个服务的支援才行。在某些新版的 distributions 中,atd 可能预设并没有启动,那么 at 这个指令就会失效呢!不过我们的 CentOS 预设是启动的!使用如下命令重启 atd 服务和配置 atd 服务开机启动:

[root@andy tmp]# /etc/init.d/atd restart
            Stopping atd:           [  OK  ]
            Starting atd:           [  OK  ]
            [root@andy tmp]# chkconfig atd on
            [root@andy tmp]# 

在执行at时,系统是如何工作的呢?事实上,我们使用 at 这个指令来产生所要运作的工作,并将这个工作以文字档的方式写入 /var/spool/at/ 目录内,该工作便能等待 atd 这个服务的取用与执行了。就这么简单。

一般用户也可以通过at命令安排自己的工作。系统对at的调用有如下限制:

at的命令格式如下:
at [-mld] time
at -c 工作号码
各个选项参数如下:

time表示在某个时间执行命令,例如at 15:30或者at 15:30 2016-06-14或者at now + 5 minutes

[jicanmeng@andy tmp]$ at 23:58
            at> /sbin/shutdown -h now
            at> 
            job 21 at 2016-06-15 23:58
            [jicanmeng@andy tmp]$ atq
            21	2016-06-15 23:58 a jicanmeng
            [jicanmeng@andy tmp]$ at -l
            21	2016-06-15 23:58 a jicanmeng
            [jicanmeng@andy tmp]$ at -c 21
                #!/bin/sh
                # atrun uid=500 gid=500
                # mail jicanmeng 0
                umask 2
                ...
                ${SHELL:-/bin/sh} << 'marcinDELIMITER406a0f99'
                /sbin/shutdown -h now

                marcinDELIMITER406a0f99
            [jicanmeng@andy tmp]$ atq
                21	2016-06-15 23:58 a jicanmeng
            [jicanmeng@andy tmp]$ at -d 21
            [jicanmeng@andy tmp]$ atq
            [jicanmeng@andy tmp]$
            [jicanmeng@andy tmp]$ cat a.sh
                #!/bin/bash

                var=1
                while [ $var -le 5 ]
                do
                    sleep 1
                    echo "after $var seconds"
                    var=$[ $var + 1 ]
                done
            [jicanmeng@andy tmp]$ date
                Thu May 19 23:08:35 CST 2016
            [jicanmeng@andy tmp]$ at -f a.sh 23:09
                job 5 at 2016-05-19 23:09
            [jicanmeng@andy tmp]$
                You have new mail in /var/spool/mail/jicanmeng
            [jicanmeng@andy tmp]$
            [jicanmeng@andy tmp]$
            [jicanmeng@andy tmp]$ mail
                Heirloom Mail version 12.4 7/29/08.  Type ? for help.
                "/var/spool/mail/jicanmeng": 2 messages 2 new
                >N  1 jicanmeng             Thu May 19 23:00  18/556   "Output from your job        1"
                 N  2 jicanmeng             Thu May 19 23:09  18/556   "Output from your job        5"
                & 2
                Message  2:
                From jicanmeng@andy.computer  Thu May 19 23:09:06 2016
                Return-Path: 
                X-Original-To: jicanmeng
                Delivered-To: jicanmeng@andy.computer
                Subject: Output from your job        5
                To: jicanmeng@andy.computer
                Date: Thu, 19 May 2016 23:09:06 +0800 (CST)
                From: jicanmeng@andy.computer (jicanmeng)
                Status: R

                after 1 seconds
                after 2 seconds
                after 3 seconds
                after 4 seconds
                after 5 seconds

                & exit
            [jicanmeng@andy tmp]$ 

at命令只在某个时间执行一次就结束了,对于那些需要在特定时间反复执行的(例如每天或每周或每个月的某个时间点都需要执行),就需要使用cron表了。at命令依赖于系统服务atd,cron则依赖于cron (crond) 这个系统服务。

对于cron的使用者的设定,和at一样,也是两个文件:/etc/cron.allow和/etc/cron.deny。

当使用者使用 crontab 这个指令来建立工作排程之后,该项工作就会被纪录到 /var/spool/cron/ 里面去了,而且是以帐号来作为判别的喔!另外, cron 执行的每一项工作都会被纪录到 /var/log/cron 这个登录档中,所以啰,如果你的 Linux 不知道有否被植入木马时,也可以搜寻一下 /var/log/cron 这个登录档呢!

cron的命令格式如下:
crontab [-u username] [-l|-e|-r] 各个选项参数如下:

[jicanmeng@andy tmp]$ crontab -l
            [jicanmeng@andy tmp]$ crontab -e
                crontab: installing new crontab
            [jicanmeng@andy tmp]$ crontab -l
                00 23 * * * mail -s "hello" jicanmeng < ~/hello.txt
            [jicanmeng@andy tmp]$ 

上面的格式表示:每天的23:00,都执行一条命令:mail -s "hello" jicanmeng < ~/hello.txt

前面说的是每个使用者自己的crontab设定文件和命令,下面说一说系统设定的crontab:/etc/crontab。 基本上, cron 这个服务的最低侦测限制是‘分钟’,所以‘ cron 会每分钟去读取一次 /etc/crontab 与 /var/spool/cron 里面的资料内容 ’,因此,只要你编辑完 /etc/crontab 这个档案,并且将他储存之后,那么 cron 的设定就自动的会来执行了!

参考资料

  1. Lnux命令行与shell脚本编程大全
  2. 鸟哥的linux私房菜
    http://vbird.dic.ksu.edu.tw/linux_basic/0430cron.php