Shell编程—控制脚本

1处理信号

1.1信号表

编号

信号名称

缺省操作

解释

1

SIGHUP

Terminate

挂起控制终端或进程

2

SIGINT

Terminate

来自键盘的中断

3

SIGQUIT

Dump

从键盘退出

4

SIGILL

Dump

非法指令

5

SIGTRAP

Dump

跟踪的断点

6

SIGABRT

Dump

异常结束

6

SIGIOT

Dump

等价于SIGABRT

7

SIGBUS

Dump

总线错误

8

SIGFPE

Dump

浮点异常

9

SIGKILL

Terminate

强迫进程终止

10

SIGUSR1

Terminate

对进程可用

11

SIGSEGV

Dump

无效的内存引用

12

SIGUSR2

Terminate

对进程可用

13

SIGPIPE

Terminate

向无读者的管道写

14

SIGALRM

Terminate

实时定时器时钟

15

SIGTERM

Terminate

进程终止

16

SIGSTKFLT

Terminate

协处理器栈错误

17

SIGCHLD

Ignore

子进程停止、结束或在被跟踪时获得信号

18

SIGCONT

Continue

如果已停止则恢复执行

19

SIGSTOP

Stop

停止进程执行

20

SIGTSTP

Stop

从tty发出停止进程

21

SIGTTIN

Stop

后台进程请求输入

22

SIGTTOU

Stop

后台进程请求输出

23

SIGURG

Ignore

套接字上的紧急条件

24

SIGXCPU

Dump

超过CPU时限

25

SIGXFSZ

Dump

超过文件大小的限制

26

SIGVTALRM

Terminate

虚拟定时器时钟

27

SIGPROF

Terminate

概况定时器时钟

28

SIGWINCH

Ignore

窗口调整大小

29

SIGIO

Terminate

I/O现在可能发生

29

SIGPOLL

Terminate

等价于SIGIO

30

SIGPWR

Terminate

电源供给失败

31

SIGSYS

Dump

坏的系统调用

31

SIGUNUSED

Dump

等价于SIGSYS

1.2捕获信号

rap命令允许你来指定shell 脚本要监看并从shell中拦截的Linux信号。trap命令的格式是:

trap commands signals

其中commands你是要执行的操作,sianals是信号(可以是信号名,也可以是信号编号)

这里有个简单例子,展示了如何使用trap命令来忽略SIGINT信号,并控制脚本的行为。

$ cat test1.sh
#!/bin/bash
# Testing signal trapping
# trap "echo ' Sorry! I have trapped Ctrl-C'" 2
# echo This is a test script
# count=1 
while [ $count -le 5 ] 
do
    echo "Loop #$count"    
    sleep 1    
    count=$[ $count + 1 ] 
done 
echo "This is the end of the test script"

本例中用到的trap命令会在每次检测到SIGINT(2)信号时显示一行简单的文本消息。捕获这些信号会阻止用户用bash shell组合键Ctrl+C来停止程序。

$ ./test1.sh
This is a test script
Loop #1
Loop #2
^C Sorry! I have trapped Ctrl-C
Loop #3
^C Sorry! I have trapped Ctrl-C
Loop #4
Loop #5
This is the end of the test script $

每次使用Ctrl+C组合键,脚本都会执行trap命令中指定的echo语句,而不是处理该信号并允许shell停止该脚本。

1.3 捕获脚本退出

除了在shell脚本中捕获信号,你也可以在shell脚本退出时进行捕获。要捕获shell脚本的退出,只要在trap命令后加上EXIT信号就行:

$ cat test2.sh
#!/bin/bash
# Trapping the script exit
trap "echo Goodbye..." EXIT
count=1 
while [ $count -le 5 ] 
do
   echo "Loop #$count" 
   sleep 1    
   count=$[ $count + 1 ] 
   done

$ ./test2.sh
Loop #1
Loop #2
Loop #3
Goodbye...

当脚本运行到正常的退出位置时或者是提退出,捕获就被触发了,shell会执行在trap命令行指定的命令。

1.4修改或移除捕获

要想在脚本中的不同位置进行不同的捕获处理,只需重新使用带有新选项的trap命令:

$ cat test3.sh
#!/bin/bash
# Modifying a set trap
trap "echo ' Sorry... Ctrl-C is trapped.'" 2
count=1 
while [ $count -le 5 ] 
do
    echo "Loop #$count"    
    sleep 1    
    count=$[ $count + 1 ] 
done  
trap "echo ' I modified the trap!'" 2
count=1 
while [ $count -le 5 ] 
do
    echo "Second Loop #$count"    
    sleep 1    
    count=$[ $count + 1 ] 
done 

修改了信号捕获之后,脚本处理信号的方式就会发生变化。但如果一个信号是在捕获被修改前接收到的,那么脚本仍然会根据最初的trap命令进行处理。

$ ./test3.sh
Loop #1
Loop #2
Loop #3
^C Sorry... Ctrl-C is trapped.
Loop #4
Loop #5
Second Loop #1
Second Loop #2
^C I modified the trap!
Second Loop #3
Second Loop #4
Second Loop #5

也可以删除已设置好的捕获。只需要在trap命令与希望恢复默认行为的信号列表之间加上破折号(-或者--)就行了:

$ cat test3b.sh 
#!/bin/bash 
# Removing a set trap 
trap "echo ' Sorry... Ctrl-C is trapped.'" SIGINT 
count=1 
while [ $count -le 5 ] 
do
    echo "Loop #$count"    
    sleep 1    
    count=$[ $count + 1 ] 
done 

# Remove the trap 
trap -- SIGINT 
echo "I just removed the trap" 
count=1 
while [ $count -le 5 ] 
do
    echo "Second Loop #$count"    
    sleep 1    
    count=$[ $count + 1 ] 
done 

$ ./test3b.sh 
Loop #1 
Loop #2 
Loop #3 
Loop #4 
Loop #5 
I just removed the trap 
Second Loop #1 
Second Loop #2 
Second Loop #3 
^C 

 

2以后台模式运行脚本

2.1后台运行脚本

以后台模式运行shell脚本非常简单。只要在命令后加个&符就行了。$ cat test4.sh

#!/bin/bash
# Test running in the background
count=1
while [ $count -le 10 ] 
do
   sleep 1
   count=$[ $count + 1 ] 
done

$ ./test4.sh &
[1] 3231

显示的第一行是:

[1] 3231

方括号中的数字是shell分配给后台进程的作业号。下一个数是Linux系统分配给进程的进程ID(PID)。Linux系统上运行的每个进程都必须有一个唯一的PID。

一旦系统显示了这些内容,新的命令行界面提示符就出现了。你可以回到shell,而你所执行的命令正在以后台模式安全的运行。这时,你可以在提示符输入新的命令

当后台进程结束时,它会在终端上显示出一条消息:

[1]   Done                    ./test4.sh

这表明了作业的作业号以及作业状态(Done),还有用于启动作业的命令。

注意,当后台进程运行时,它仍然会使用终端显示器来显示STDOUT和STDERR消息。所以最好将消息重定向,不然会导致屏幕信息混乱。

2.2运行多个后台作业

可以在命令行提示符下同时启动多个后台作业。

$ ./test6.sh &
[1]  3568
$ This is Test Script #1
 
$ ./test7.sh &
[2]  3570
$ This is Test Script #2
 
$ ./test8.sh &
[3]  3573
$ And...another Test script
 
$ ./test9.sh &
[4]  3576
$ Then...there was one more test script

每次启动新作业时,Linux系统都会为其分配一个新的作业号和PID。通过ps命令,可以看到所有脚本处于运行状态。

$ ps
  PID TTY          TIME CMD
 2431 pts/0    00:00:00 bash
 3568 pts/0    00:00:00 test6.sh
 3570 pts/0    00:00:00 test7.sh
3573  pts/0    00:00:00 test8.sh
3574  pts/0    00:00:00 sleep
3575  pts/0    00:00:00 sleep
3576  pts/0    00:00:00 test9.sh
3577  pts/0    00:00:00 sleep
3578  pts/0    00:00:00 sleep
3579  pts/0    00:00:00 ps

注意,在ps命令的输出中,每一个后台进程都和终端会话(pts/0)终端联系在一起。如果终端会话退出,那么后台进程也会随之退出。

 

3       在非控制台下运行脚本

nohup命令运行了另外一个命令来阻断所有发送给该进程的SIGHUP信号。这会在退出终端会话时阻止进程退出。

nohup命令的格式如下:

$ nohup ./test1.sh & 
[1] 3856
$ nohup: ignoring input and appending output to 'nohup.out'

和普通后台进程一样,shell会给命令分配一个作业号,Linux系统会为其分配一个PID号。区别在于,当你使用nohup命令时,如果关闭该会话,脚本会忽略终端会话发过来的SIGHUP信号。 6由于nohup命令会解除终端与进程的关联,进程也就不再同STDOUT和STDERR联系在一起。为了保存该命令产生的输出,nohup命令会自动将STDOUT和STDERR的消息重定向到一个名为nohup.out的文件中。

在进程完成运行后,你可以查看nohup.out文件中的输出结果:

$ cat nohup.out
This is a test script
Loop 1
Loop 2 
Loop 3 
Loop 4 
Loop 5 
Loop 6
Loop 7
Loop 8
Loop 9
Loop 10
This is the end of the test script
posted @ 2019-12-15 19:58  橘子洲头。  阅读(301)  评论(0编辑  收藏  举报