Linux Shell 脚本的运行控制

7 篇文章 0 订阅

1. Linux 中的信号;

  • 类似于 CPU 中“软中断”的概念,它用来进行进程间的异步通信。信号由一个进程发出,由另一个进程接收并处理。

1.1 产生信号;

# 查看 Linux 中对信号的支持
man 7 signal	# 以下列出只要信号和值
信号         值      动作   说明
─────────────────────────────────────────────────────────────────────
 SIGHUP        1       A     在控制终端上是挂起信号, 或者控制进程结束
 SIGINT        2       A     从键盘输入的中断
 SIGQUIT       3       C     从键盘输入的退出
 SIGILL        4       C     无效硬件指令
 SIGABRT       6       C     非正常终止, 可能来自 abort(3)
 SIGFPE        8       C     浮点运算例外
 SIGKILL       9      AEF    杀死进程信号
 SIGSEGV      11       C     无效的内存引用
 SIGPIPE      13       A     管道中止: 写入无人读取的管道
 SIGALRM      14       A     来自 alarm(2) 的超时信号
 SIGTERM      15       A     终止信号
 SIGUSR1   30,10,16    A     用户定义的信号 1
 SIGUSR2   31,12,17    A     用户定义的信号 2
 SIGCHLD   20,17,18    B     子进程结束或停止
 SIGCONT   19,18,25          继续停止的进程
 SIGSTOP   17,19,23   DEF    停止进程
 SIGTSTP   18,20,24    D     终端上发出的停止信号
 SIGTTIN   21,21,26    D     后台进程试图从控制终端(tty)输入
 SIGTTOU   22,22,27    D     后台进程试图在控制终端(tty)输出

# 1. 键盘组合键(产生信号)
# 终止进程:SIGINT Ctrl + C
# 暂停进程:SIGSTP Ctrl + Z
# 演示:
ping www.baidu.com	# 如果不加限制,命令会一直运行
Ctrl + C			# 停止 ping 命令执行

ping www.baidu.com
Ctrl + Z			# 暂停 ping 命令执行
ps -ef | grep ping 	# ping 还在进程中
root     11530  9827  0 14:57 pts/0    00:00:00 ping www.baidu.com
root     11536  9827  0 14:58 pts/0    00:00:00 grep --color=auto ping
# 过程是通过键盘上的“Ctrl+C”和“Ctrl+Z”分别产生了不同的信号
# 系统会将这个信号传递给正在运行中的“ping”命令
# “ping”命令在接收到信号之后以默认的形式对信号做出了处理和响应

# 2. 常用命令(产生信号)
# kill 和变种 killall
# 本质是传递一个信号给进程,而进程最终的停止是通过对这个信号的处理而完成的
# 演示
ping www.baidu.com
Ctrl + Z
ps			# ping 还在运行中
9827 pts/0    00:00:00 bash
11530 pts/0    00:00:00 ping
11554 pts/0    00:00:00 ps
kill -9 11530	# 通过 ping 命令的进程号终止 ping 进程

1.2 处理信号;

  • 按照默认方式处理信号,遵循信号原本的含义来进行信号的处理。如果在程序中不指定任何的信号操作,系统会按照默认的形式来处理信号
  • 忽略信号
  • 按照自定义的方式处理信号
# 在脚本中用来处理捕捉信号的命令:trap
cd /data/shellscript	# 演示文件所在文件夹
mkdir ctrltest
cd ctrltest

touch traptest
chmod +x traptest
vim traptest
# 写入以下内容
#! /bin/bash

# 使用 trap 命令对 SIGINT 信号进行捕捉
# 这个信号就是“Ctrl+C”按键发出的信号
# 使用 trap 命令捕捉以后,进行了一个文本的输出
# 原有的“Ctrl+C”停止程序的信号就被改变了
# 改为了输出以下指定的文本
trap "echo 'signal trapped SIGINT for Ctrl+C'" SIGINT

# 简单的 1-10 循环输出
count=1
while [ $count -le 10 ]
do
	echo "loop # $count"
	sleep 1
	count=$[ $count + 1]
done
echo "loop ended"

# 保存退出,运行
./traptest	# 输出
loop # 1
loop # 2
loop # 3
loop # 4
loop # 5
^Csignal trapped SIGINT for Ctrl+C
loop # 6
loop # 7
loop # 8
loop # 9
^Csignal trapped SIGINT for Ctrl+C
loop # 10
loop ended

# 除了捕捉信号,trap 命令也可以捕捉到程序的退出状态
vim traptest
# 写入以下内容
#! /bin/bash

# trap "echo 'signal trapped SIGINT for Ctrl+C'" SIGINT
trap "echo 'quit script'" EXIT
count=1
while [ $count -le 5 ]
do
	echo "loop # $count"
	sleep 1
	count=$[ $count + 1]
done
echo "loop ended"

# 保存退出,运行
./traptest	# 输出
loop # 1
loop # 2
loop # 3
loop # 4
loop # 5
loop ended
quit script

# 可以在程序中对已经添加的 trap 进行移除
# 语法
trap - EXIT
# 根据之前的例子,在循环解释 done 之后添加,就不会输出“quit script”这个文本

2. 后台运行脚本;

  • 不运行在终端显示器上的进程,称之为后台(bacground)运行进程
# 后台运行命令格式:
SCRIPT &
# 举例:
./traptest		# 前台运行脚本,此时界面不能进行输入(输入无效)
Ctrl + Z		# 返回:[1]+  已停止  ./traptest
./traptest &	# 后台运行脚本,返回: [2] 11712
# 11712 就是进程的id(pid),数字“2”就是作业号。
# 作业就是当前执行的任务。之前“Ctrl+Z”返回一个“1”也是一个作业
# 之前后台运行的脚本 traptest 结束后点击回车,
# 显示:[2]-  完成  ./traptest
# 可以同时运行多个后台程序,每次运行都会返回新的:[作业号]+进程
# 与运行前台进程不同,在运行后台进程时依旧可以在 Shell 中进行命令的执行
# 虽然后台进程也在前台输出,但是整个运行是在后台进行的

# 查看正在进行中的作业,就要用到“jobs”命令:
jobs			# 返回:
[1]+  已停止               ./traptest
[2]-  运行中               ./traptest &
# 一共两个作业,第一个前台作业停止,第二个是后台作业正在运行中
# 通过 jobs 命令可以查询所有作业的状态
# 已经结束的作业使用 jobs 无法查询

# 可以让已经停止的命令重新运行起来,使用“fg”命令:
# 通过前台的形式重新启动作业
fg 1			# fg + 作业号
Ctrl + Z
# 如果要通过后台启动一个停止的作业,使用“bg”命令
bg 1

# 对于多个运行在后台的作业
# 可以通过设定优先级来指定系统分配给每个进程上的 CPU 时间

# 作业的优先级
# 优先级范围:-20(高)~ 19(低)
# 优先级设定:nice
# 演示
nice -n 10 ./traptest > temp &	
# nice 启动脚本, -n 选项指定优先级为 10,输出重定向至 temp
# 返回: [2] 11755
ps al	# 查看当前运行的优先级,返回:
F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
0 S     0 11755 11560  0  90  10 - 28295 do_wai pts/0    00:00:00 traptest
0 S     0 11759 11755  0  90  10 - 26988 hrtime pts/0    00:00:00 sleep
0 R     0 11760 11560  0  80   0 - 38309 -      pts/0    00:00:00 ps
# NI 栏位,显示优先级 10

# 优先级重新设定:renice
renice -20 -p 11755
# 返回: 11755 (进程 ID) 旧优先级为 10,新优先级为 -20

# 脱离控制台限制
# 如果关闭脚本运行床后,重新打开
# 脚本会随着我们关闭窗口退出执行
# 脚本如何不与 Bash 窗口相关联?使用 nohup 命令
# 演示:
nohup ./traptest &
# 返回:
[2] 11797
[root@localhost ctrltest]# nohup: 忽略输入并把输出追加到"nohup.out"
# nohup 作用就是将后台运行的脚本与当前的 Bash 控制台相分离

3. 定时运行脚本;

  • 在进行日常的服务器维护和以及应用程序的维护时,通常需要定时的进行日志的清理和操作。这时就需要有一个定时的机制来运行相应的程序。
# 1. 最简单的以“指定时间”的方式来运行脚本
# 语法格式
at [ -f filename ] time
# time 时间格式:
10:15
10:15~PM
now、noon、teatime
MMDDYY、MM/DD/YY、MM.DD.YY
Jun 14、Dec 25
now+25min

# 演示:
# 安装 at 命令
yum -y install at	
chkconfig --level 35 atd on
service atd start

touch attest
chmod +x attest
vim attest
# 写入以下内容
#! /bin/bash

# 使用重定向进行输出处理
# 因为默认情况下,“at”命令会将标准的错误以邮件的形式发送到指定的、用户关联的邮箱中
# 在日常使用中,通常不会这样操作,所以在脚本开头使用标准输出重定向
exec 1>>atresult

echo "script run at `date`"
echo "end script"

# 保存退出后运行
# -M 选项:不使用邮件输出
# -f 指定脚本
at -M -f ./attest now+1min
# 返回:
job 1 at Sat Jul 27 21:45:00 2019

# 查看 at 命令的运行队列
atq
# 返回 
1       Sat Jul 27 21:45:00 2019 a root

# 删除一个还没有运行的任务
atrm 1

# 2. 指定周期运行
# 使用 cron 时间表
# 查看 cron 时间表格式
vim /etc/crontab
# 返回
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
# For details see man 4 crontabs
# Example of job definition:
# .---------------- minute (0 - 59)
# |  .------------- hour (0 - 23)
# |  |  .---------- day of month (1 - 31)
# |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
# |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# |  |  |  |  |
# *  *  *  *  * user-name  command to be executed

# 查看配置文件夹下关于 cron 更多信息
ls /etc/cron*
# 包含了 /etc/cron.daily、/etc/cron.hourly、/etc/cron.monthly、/etc/cron.weekly
# 四个最主要的文件夹
# 可以将需要进行周期运行的脚本复制在这几个文件夹下
# 它就会根据 /etc/crontab 这个文件去按周期运行
# 也可以编辑自己的,但是如果想非常精确的指定运行时间
# 我们就需要进行“用户cron表”的编辑
crontab -e 	# 修改当前用户时间表
# 编辑:每天凌晨2点执行一个命令
0 2 * * * /data/shellscript/ctrltest/attest
# 保存退出
crontab -l	# 列出当前用户的计划时间表
# 返回
0 2 * * * /data/shellscript/ctrltest/attest

# cron 程序是假设系统是 7*24 小时来运行的
# 如果在指定的时间内并没有开机,指定的计划任务就不会执行
# 如果要解决这个问题,就需要使用另一个命令,也就是异步的 cron
# 查看
vim /etc/anacrontab
# anacron 程序也是在读取刚才提到的 cron 的配置
# 包括了 daily、weekly、monthly 的配置
# anacron 程序并不能处理频率大于“一天一次”的计划
# 所以最小配置就是 daily

4. 启动时运行脚本。

  • 系统启动时运行:当 Linux 启动时,自动运行脚本。

  • 开机过程:

    • System V init
    • Upstart init
  • 进行自定义开机脚本的配置与 Linux 的文件式思想是一致的。只需要修改 Linux 的一些配置文件就能后实现

  • 开机运行脚本

    • debian :/etc/init.d/rc.local
    • Ubuntu :/etc/rc.local
    • openSUSE :/etc/init.d/boot.local
    • CentOS/etc/rc.d/rc.local
# 一般是在 /etc/profile 中进行环境变量的设置
# 在通常的情况下,在开发中使用环境变量,会将配置写在 /etc/profile 这个文件中
# 但是这样的配置并不足以在开机启动时能够启动一些服务器

# 以 Nginx 为例,如果要启动 Nginx 服务器,就需要使用 Nginx 的启动脚本
# 如果重启计算机,并不做登录操作,服务器就会是不可用状态
# 那是因为没有在开机的启动文件中执行 Nginx 的启动脚本
vim /etc/rc.d/rc.local		# 相当于 vim /etc/rc.local	
# 在启动脚本之前可以将标准输出重定向至一个文件中,标准错误重定向至日志文件的错误中
exec 1>>/home/hualaoshuan/logs/startup/logs
exec 2>>/home/hualaoshuan/logs/startup/error
# 然后将希望启动的命令填在此文件就可以

# 但是不要把所有的启动脚本都配置在 /etc/rc.d/rc.local 中,
# 否则这个文件会非常庞大难以维护
# 通常会将特定功能的配置脚本进行组合,
# 也就是将相应功能的一系列命令写到一个文件中
# 然后再 /etc/rc.d/rc.local 中进行调用
# 以上就是如何在 Linux 中进行启动脚本配置,还有错误调试。
  • Shell 启动时运行

    • 启动 bash:/etc/profile$HOME/.bashrc
    • 通过 ssh 登录:/etc/profile$HOME/.bashrc
    • 通过 ssh 执行命令:$HOME/.bashrc
  • 前两种 Shell 启动方式和最后一种有一些细微的差别。通过 ssh 直接执行命令不会经过 login 的过程,而是直接启动

  • 如果 ssh 指定了命令,那么它会在远程的主机执行,并不会进行 Shell 的登录。因此使用 ssh 直接执行命令,Shell 中并不会调用 /etc/profile 文件中指定的设置,而是只会调用 $HOME/.bashrc 这个文件

  • 所以在进行自启动脚本配置的时候,就要特别的注意,当我们要运行的脚本和一定的配置需要在 ssh 远程执行命令的时候依然对有效的话,那么必须将配置写在 $HOME/.bashrc 这个文件中

# 系统启动时 /etc/profile 和 $HOME/.bashrc 都会加载所有 /etc/profile.d/*.sh 文件
# 一些环境变量可以写在 /etc/profile.d/*.sh 里启动加载

# 一些**启动脚本**可以放在 /etc/init.d 目录下
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值