1. 处理信号
1.1 重温Linux信号
Linux系统和应用程序可以生成超过30
个信号。表16-1列出了在Linux编程时会遇到的最常见
的Linux系统信号。
通过SIGINT信号,可以中断shell。
你可能也注意到了,shell会将这些信号传给shell脚本程序来处理。而shell脚本的默认行为 是忽略这些信号。它们可能会不利于脚本的运行。要避免这种情况,你可以脚本中加入识别信
号的代码,并执行命令来处理信号。
1.2 生成信号
中断进程
Ctrl+C
组合键会生成SIGINT
信号
$ sleep 100 ^C
$
暂停进程
Ctrl+Z
组合键会生成一个SIGTSTP
信号,停止shell中运行的任何进程。停止(stopping)进程跟终止(terminating)进程不同:停止进程会让程序继续保留在内存中,并能从上次停止的位置继续运行
。
当用Ctrl+Z组合键时,shell会通知你进程已经被停止了。
$ sleep 100 ^Z
[1]+ Stopped sleep 100
$
方括号中的数字是shell分配的作业号(job number
)。shell将shell中运行的每个进程称为作业, 并为每个作业分配唯一的作业号。它会给第一个作业分配作业号1,第二个作业号2,以此类推。
可以用ps命令
来查看已停止的作业。
$ sleep 100 ^Z
[1]+ Stopped $
sleep 100
$ ps -l
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
0 S 501 2431 2430 0 80 0 - 27118 wait pts/0 00:00:00 bash
0 T 501 2456 2431 0 80 0 - 25227 signal pts/0 00:00:00 sleep
0 R 501 2458 2431 0 80 0 - 27034 - pts/0 00:00:00 ps
$
在S列
中(进程状态),ps命令将已停止作业的状态为显示为T
。这说明命令要么被跟踪,要 么被停止了。
如果在有已停止作业存在的情况下,你仍旧想退出shell,只要再输入一遍exit
命令就行了。 shell会退出,终止已停止作业。或者,既然你已经知道了已停止作业的PID,就可以用kill
命令 来发送一个SIGKILL信号来终止它。
$ kill -9 2456 $
[1]+ Killed sleep 100
$
捕获信号
trap命令允许你来指定shell 脚本要监看并从shell中拦截的Linux信号。如果脚本收到了trap命令中列出的信号,该信号不再 由shell处理,而是交由本地处理。
trap命令的格式是:
trap commands signals
这里有个简单例子,展示了如何使用trap命令来忽略SIGINT信号,并控制脚本的行为。
$ cat test1.sh
#!/bin/bash
# Testing signal trapping
#
trap "echo ' Sorry! I have trapped Ctrl-C'" SIGINT #
echo This is a test script
#
count=1
while [ $count -le 10 ]
do
echo "Loop #$count"
sleep 1
count=$[ $count + 1 ]
done
#
echo "This is the end of the test script"
#
捕获这些 信号会阻止用户用bash shell组合键Ctrl+C来停止程序。每次使用Ctrl+C组合键,脚本都会执行trap命令中指定的echo语句,而不是处理该信号并允许shell停止该脚本。
$ ./test1.sh
This is a test script
Loop #1
Loop #2
Loop #3
Loop #4
Loop #5
^C Sorry! I have trapped Ctrl-C Loop #6
Loop #7
Loop #8
^C Sorry! I have trapped Ctrl-C Loop #9
Loop #10
This is the end of the test script $
2. 在非控制台下运行脚本
有时你会想在终端会话中启动shell脚本,然后让脚本一直以后台模式运行到结束,即使你退 出了终端会话。这可以用nohup命令来实现。
nohup命令运行了另外一个命令来阻断所有发送给该进程的SIGHUP信号。这会在退出终端会话时阻止进程退出。
nohup命令的格式如下:
$ nohup ./test1.sh &
[1] 3856
$ nohup: ignoring input and appending output to 'nohup.out'
$
由于nohup命令会解除终端与进程的关联,进程也就不再同STDOUT和STDERR联系在一起。为了保存该命令产生的输出,nohup命令会自动将STDOUT和STDERR的消息重定向到一个名为 nohup.out的文件中。