19.Linux Shell任务控制
文章目录
- Linux Shell任务控制
- 1)信号
- 通过键盘生成信号
- trap 命令捕获信号
- 2)在后台运行脚本
- 命令后加 & 符
- 使用nohub命令
- 3)作业控制
- 4)调度优先级
- nice命令
- renice 命令
- 5)定时运行作业
- at
- 定期执行命令
- reference
欢迎访问个人网络日志🌹🌹知行空间🌹🌹
Linux Shell任务控制
通常情况下运行脚本的方式就是以实时模式在命令行界面上直接运行,除此之外还有很多其他的运行脚本的方式,如后台运行,定时运行等等。除运行方式外,还可以对脚本程序的运行进行控制,包括向脚本发送信号、修改脚本的优先级以及在脚本运行时从暂停切换到运行模式。
1)信号
Linux
利用信号与运行在系统中的进程进行通信,可以通过对脚本进行编程,使其在收到特定信号时执行特定命令。
信号 | 值 | 描述 |
---|---|---|
1 | SIGHUP | 挂起进程 |
2 | SIGINT | 终止进程 |
3 | SIGQUIT | 停止进程 |
9 | SIGKILL | 无条件终止进程 |
15 | SIGTERM | 尽可能终止进程 |
17 | SIGSTOP | 无条件停止进程,但不是终止进程 |
18 | SIGTSTP | 停止或暂停进程,但不终止进程 |
19 | SIGCONT | 继续运行停止的进程 |
默认情况下,交互式shell
终端本身的进程会忽略收到的任何 SIGQUIT (3)
和 SIGTERM (5)
信号,因此其不会被意外终止。
如果bash shell
收到了 SIGHUP
信号,比如当要离开一个交互式shell
时,它就会退出。但在退出之前,它会将 SIGHUP
信号传给所有由该shell
所启动的进程。
通过键盘生成信号
Ctrl+C
组合键会生成 SIGINT
信号,并将其发送给当前在shell
中运行的所有进程。
Ctrl+Z
组合键会生成一个 SIGTSTP
信号,停止shell
中运行的任何进程。这样可以在进程运行期间暂停进程,而无需终止它。这样可以在不终止进程的情况下使用户深入脚本内部一窥究竟。
停止进程会让程序继续保留在内存中,并能从上次停止的位置继续运行。
要想启动停止的进程可以使用fg
或bg
在前台和后台启动。
$ sleep 100
# ^Z
# [1]+ 已停止 sleep 100
方括号中的数字是shell
分配的作业号 (job number)
。
可以用 ps
命令来查看已停止的作业。
$ ps -l
# F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
# 0 T 1001 116014 113239 0 80 0 - 2791 do_sig pts/0 00:00:00 sleep
在 S
列中(进程状态), ps
命令将已停止作业的状态为显示为 T
。这说明命令要么被跟踪,要么被停止了。
在有已停止作业存在的情况下退出shell
会终止已停止作业。
trap 命令捕获信号
trap
命令允许用户来指定shell
脚本要监视并从shell
中拦截的Linux
信号。当脚本收到了 trap
命令中列出的信号,会执行用户指定的操作。
trap
命令的格式:
trap commands signals
示例,
#!/bin/bashtrap "echo 'Ctrl-C Pressed'" SIGINTecho This is a testc=1
while [ $c -le 5 ]
doecho "Loop #$c"sleep 1c=$[ $c + 1 ]
done
执行,
$ ./test.sh
# This is a test
# Loop #1
# Loop #2
# ^CCtrl-C Pressed
# Loop #3
# Loop #4
# Loop #5
上面脚本中trap
命令会在每次检测到 SIGINT
信号时捕获这些信号,阻止用户用bash shell
组合键Ctrl+C
来停止程序。
除了在shell
脚本中捕获中断信号,也可以在shell
脚本退出时捕获退出信号EXIT
。以在shell
完成任务时执行特定的命令。
#!/bin/bashtrap "echo 'Running Finished.'" EXITecho This is a testc=1
while [ $c -le 5 ]
doecho "Loop #$c"sleep 1c=$[ $c + 1 ]
done
执行,
$ ./test.sh
# This is a test
# Loop #1
# Loop #2
# Loop #3
# Loop #4
# Loop #5
# Running Finished.
要修改移除捕获,在脚本中的不同位置进行不同的捕获处理,只需重新使用带有新选项的 trap
命令。
#!/bin/bashtrap "echo 'Caught SIGINT'" SIGINTecho "This is first caughtion of SIGINT"c=1
while [ $c -le 3 ]
doecho "Loop #$c"sleep 1c=$[ $c + 1 ]
donetrap "echo 'Redefine SIGINT '" SIGINT
echo "This is Mutated caughtion of SIGINT"
sleep 10
执行,
$ ./test.sh
# This is first caughtion of SIGINT
# Loop #1
# ^CCaught SIGINT
# Loop #2
# Loop #3
# This is Mutated caughtion of SIGINT
# ^CRedefine SIGINT
修改了信号捕获之后,脚本处理信号的方式就会发生变化。如果一个信号是在捕获被修改前接收到的,那么脚本仍然会根据最初的 trap
命令进行处理。
想删除已设置好的捕获,只需要在 trap
命令与希望恢复默认行为的信号列表之间加上两个破折号即可。
trap -- SIGINT
2)在后台运行脚本
直接在命令行界面运行shell
脚本,脚本在运行时,没法在终端会话里做别的事情。
在用 ps
命令时,会看到运行在Linux
系统上的一系列不同进程。这些进程显然都不是运行在当前的终端显示器上的,这种模式称为在后台运行进程。在后台模式中,进程运行时不会和终端会话上的 STDIN
、 STDOUT
以及 STDERR
关联。
命令后加 & 符
前面介绍过,以后台模式运行shell
脚本,只要在命令后加个 & 符就行。
$ ./test.sh &
# [1] 118347
方括号中的数字是shell
分配给后台进程的作业号。下一个数是Linux
系统分配给进程的进程ID(PID)
。当后台进程结束时,它会在终端上显示出一条消息:
# [1]+ 已完成 ./test.sh
通过./test.sh &
命令将脚本放在后台运行还存在两个问题,一个是当前bash shell
终端关闭时后台运行中的进程仍然会被终止,第二个时放入后台的脚本输出仍然会显示在显示器上,会与新输入命令的输入混淆在一起。
运行多个后台作业时,通过 ps
命令,可以看到
所有脚本处于运行状态。
./test.sh &./test.sh &
$ ps
# F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
# 0 S 1001 118703 118697 0 80 0 - 3178 do_wai pts/3 00:00:00 test.sh
# 0 S 1001 118707 118703 0 80 0 - 2791 hrtime pts/3 00:00:00 sleep
# 0 S 1001 118714 118697 0 80 0 - 3178 do_wai pts/3 00:00:00 test.sh
# 0 S 1001 118718 118714 0 80 0 - 2791 hrtime pts/3 00:00:00 sleep
使用nohub命令
当需要在终端会话中启动shell
脚本,然后让脚本一直以后台模式运行到结束,且终端会话退出仍不影响脚本运行时,前面介绍的&
符号的方式就不适合了,这时需要使用nohub
命令。
nohup
命令运行的后台任务会阻断所有发送给该进程的 SIGHUP
信号,这可以在退出终端会话时阻止进程退出。
nohup
命令的格式:
$ nohup ./test.sh &
# [1] 119226
# nohup: 忽略输入并把输出追加到'nohup.out'
由于 nohup
命令会解除终端与进程的关联,进程也就不再同 STDOUT
和 STDERR
联系在一起。
为了保存该命令产生的输出, nohup
命令会自动将 STDOUT
和 STDERR
的消息重定向到一个名为
nohup.out
的文件中。值得注意的是,当在同个目录同时启动多个nohub
命令时,会输出到同一个nohub.out
文件中。
3)作业控制
jobs
命令可以查看分配给shell
的作业。
通过test.sh
启动两个作业,
$ ./test.sh
# This is first caughtion of SIGINT
# Loop #1
# ^Z
# [1]+ 已停止
$ ./test.sh > test.out &
# [2] 119480
$ jobs
# [1]+ 已停止 ./test.sh
# [2]- 运行中 ./test.sh > test.out &
要想查看作业的PID
,可以在 jobs
命令中加入 -l
选项。jobs
命令输出中的加号和减号的含义是带加号的作业会被当做默认作业,在使用作业控制命令时,如果未在命令行指定任何作业号,该作业会被当成作业控制命令的操作对象。当前的默认作业完成处理后,带减号的作业成为下一个默认作业。任何时候都只有一个带加
号的作业和一个带减号的作业。在前面介绍的重新启动停止的作业的命令fg/bg
不带参数时,启动的就是+
号对应的作业。
更多jobs
命令的选项参数,可以通过命令jobs --help
查看。
4)调度优先级
调度优先级决定了内核分配给进程的CPU时间。在Linux
系统中,由shell
启动的所有进程的调度优先级默认都是相同的,都是0
。调度优先级是个整数值,从-20
(最高优先级)到+19
(最低优先级)。
要改变一个shell
脚本的优先级,可以通过 nice
命令做到。
nice命令
nice
命令允许你设置命令启动时的调度优先级。要让命令以更低的优先级运行,只要用 nice
的 -n
命令行来指定新的优先级即可。
$ nice -n 10 ./test.sh > test.out &
# [2] 120413
$ ps -p 120413 -o pid,ppid,ni,cmd
# PID PPID NI CMD
# 120413 118697 10 /bin/bash ./test.sh
通过ps
命令可以看到调度优先级已经被调整到了10
。
nice
命令阻止普通系统用户来提高命令的优先级,需要使用root
权限。
renice 命令
renice
命令用来改变系统上已运行命令的优先级。通过指定运行进程的PID来改变它的优先级。
$ renice -n 10 -p 120756
# 120756 (process ID) 旧优先级为 0,新优先级为 10
5)定时运行作业
Linux
系统提供了多个在预选时间运行脚本的方法: at
命令和 cron
表。
at
at
命令允许指定Linux
系统何时运行脚本,相当于是预约执行任务。
at
的守护进程 atd
会以后台模式运行,检查作业队列来运行作业。大多数Linux
发行版会在启动时运行此守护进程。
atd
守护进程会检查系统上的一个特殊目录(通常位于/var/spool/at
)来获取用 at
命令提交的作业。默认情况下, atd
守护进程会每60秒检查一下这个目录。有作业时, atd
守护进程会检查作业设置运行的时间。如果时间跟当前时间匹配, atd` 守护进程就会运行此作业。
at
命令的基本格式:
at [-f filename] time
-f
参数来指定用于读取命令(脚本文件)的文件名。time
参数指定了Linux系统何时运行该作业。
at
命令能识别多种不同的时间格式:
- 标准的小时和分钟格式,比如
22:15
AM/PM
指示符,比如10:15 PM
- 特定可命名时间,比如
now
、noon
、midnight
或者teatime(4 PM)
- 通过不同的日期格式指定特定的日期
- 标准日期格式,比如MMDDYY、MM/DD/YY或DD.MM.YY
- 文本日期,比如Jul 4或Dec 25,加不加年份均可
- 指定时间增量:当前时间+25 min。
$ at -f test.sh 21:23
# warning: commands will be executed using /bin/sh
# job 3 at Mon Jan 8 21:23:00 2024
作业队列的字母排序越高,作业运行的优先级就越低,nice
值更高。默认情况下, at
的作业会被提交到 a
作业队列。如果想以更高优先级运行作业,可以用 -q
参数指定不同的队列字母。
在使用 at
命令时,最好在脚本中对 STDOUT
和 STDERR
进行重定向。
atq
命令可以查看系统中有哪些作业在等待。
$ atq
# 1 Mon Jan 8 21:17:00 2024 = rob
# 6 Tue Jan 9 20:24:00 2024 a rob
# 3 Mon Jan 8 21:23:00 2024 = rob
# 4 Tue Jan 9 20:24:00 2024 a rob
# 5 Tue Jan 9 20:24:00 2024 a rob
可以用 atrm
命令来删除等待中的作业。
$ atrm 6
$ atq
# 1 Mon Jan 8 21:17:00 2024 = rob
# 3 Mon Jan 8 21:23:00 2024 = rob
# 4 Tue Jan 9 20:24:00 2024 a rob
# 5 Tue Jan 9 20:24:00 2024 a rob
定期执行命令
at
命令可以在预设时间安排脚本执行,但如果需要脚本在每天的同一时间运行或是每周一次、每月一次就需要使用新方法。
Linux
系统使用cron
程序来安排要定期执行的作业。 cron
程序会在后台运行并检查cron
时间表,以获知已安排执行的作业。
可以使用crontab -e
来编辑cron
时间表:
$ crontab -e
# GNU nano 4.8 /tmp/crontab.hABXZo/crontab
# # Edit this file to introduce tasks to be run by cron.
# #
# # Each task to run has to be defined through a single line
# # indicating with different fields when the task will be run
# # and what command to run for the task
表中每一行表示一个定期执行的任务,其格式为:
# m h dom mon dow command
m
表示分钟,
h表示小时,
dom表示几号,
mon表示月份,
dow表示星期几,
*`表示任意日期。
分别是:minute (m), hour (h), day of month (dom), month (mon),# and day of week (dow) or use '*' in these fields (for 'any')
示例:
# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/
表示每周一凌晨5点将home.tgz
解压到/home
路径中。
每月最后一天执行的任务设置方式,
# 00 12 * * * if [ ` date +%d -d tomorrow ` = 01 ] ; then ; command
列出crontab
中的任务:
crontab -l
如果待执行的脚本对精确的执行时间要求不高,用预配置的cron脚本目录会更方便。在/etc/
路径下有4个基本目录:cron.hourly、daily、monthly
和weekly
。譬如,如果脚本需要每天运行一次,只要将脚本复制到daily
目录,cron
就会每天执行它。
cron
程序的唯一问题是它假定Linux系统是7×24小时运行的,如果系统存在关机重启,有可能会错误定时任务,处理这种情况最好是能在开机时检查是否有错过的定时任务,而cron
并不会去检查,很多Linux
发行版还包含了anacron
程序可以解决这个问题。
anacron
程序只会处理位于cron
目录的程序,比如/etc/cron.monthly
。它用时间戳来决定作业是否在正确的计划间隔内运行了。每个cron
目录都有个时间戳文件,该文件位于/var/spool/anacron
。
$ sudo cat /var/spool/anacron/cron.monthly
# 20240104
欢迎访问个人网络日志🌹🌹知行空间🌹🌹
reference
1.《Linux命令行与shell脚本编程大全》
相关文章:
19.Linux Shell任务控制
文章目录 Linux Shell任务控制1)信号通过键盘生成信号trap 命令捕获信号 2)在后台运行脚本命令后加 & 符使用nohub命令 3)作业控制4)调度优先级nice命令renice 命令 5)定时运行作业at定期执行命令reference 欢迎访问个人网络日志🌹🌹知行空间&#x…...

域名流量被劫持怎么办?如何避免域名流量劫持?
随着互联网不断发展,流量成为线上世界的巨大财富。然而一种叫做域名流量劫持的网络攻击,将会在不经授权的情况下控制或重定向一个域名的DNS记录,导致用户在访问一个网站时,被引导到另一个不相关的网站,从而劫持走原网站…...

java案例知识点
一.会话技术 概念 技术 二.跨域 三.过滤器 四.拦截器...
Arrays 的使用
Arrays 概述 提供了数组操作的相关方法,连接数组和集合 asList 返回指定数组的列表列表和数组的引用位置相同 Integer[] arrs new Integer[] {1,2,3,4,5,6,7,8,9};List<Integer> list Arrays.asList(arrs);System.out.println(list);arrs[5] 100;Syste…...

IDEA中怎么用Postman?这款插件你试试
Postman是大家最常用的API调试工具,那么有没有一种方法可以不用手动写入接口到Postman,即可进行接口调试操作?今天给大家推荐一款IDEA插件:Apipost Helper,写完代码就可以调试接口并一键生成接口文档!而且还…...

基于机器视觉的车牌检测-边缘检测因子的选择
车牌检测概述 车牌识别在检测报警、汽车出入登记、交通违法违章以及移动电子警察方面应用广泛。车牌识别过程为:首先通过摄像头获取包含车牌的彩色图像;然后进行车牌边缘检测,先粗略定位到车牌位置,再精细定位;最后根…...

学习c语言,变种水仙花
利用函数次方pow...

K8S--持久卷(PersistentVolume)的用法
原文网址:K8S--持久卷(PersistentVolume)的用法-CSDN博客 简介 本文介绍K8S的持久卷(PersistentVolume)的用法。 目标:用持久卷的方式将主机的磁盘与容器磁盘映射,安装nginx并运行。 --------------------------------------------------…...

书生·浦语大模型趣味 Demo笔记及作业
文章目录 笔记作业基础作业:进阶作业: 笔记 书生浦语大模型InternLM-Chat-7B 智能对话 Demo:https://blog.csdn.net/m0_49289284/article/details/135412067书生浦语大模型Lagent 智能体工具调用 Demo:https://blog.csdn.net/m0_…...

2024最新前端源码分享(附效果图及在线演示)
分享10款非常有趣的前端特效源码 其中包含css动画特效、js原生特效、svg特效以及小游戏等 下面我会给出特效样式图或演示效果图 但你也可以点击在线预览查看源码的最终展示效果及下载源码资源 粒子文字动画特效 基于canvas实现的粒子文字动画特效 会来回切换设定的文字特效 图…...

Microsoft 365 for Mac激活版(原Office 365)
Microsoft 365 for Mac原office 365,包含Word、Excel、PowerPoint 和 Outlook应用程序,协作办公的最佳首选。 软件下载:Microsoft 365 for Mac激活版下载 Microsoft 365 的一些主要功能包括: office 应用程序:Microsof…...

快乐学Python,Python基础之组织代码「类与对象」
在上一篇文章中,我们了解了函数。这一篇文章我们来了解一下Python中另外一个重要的概念:类与对象。 1、类与对象 (1)类与对象有什么关系? 你可能会奇怪,为什么要叫类与对象呢?是两个不同的东…...
H5的3D游戏开源框架
在H5的3D游戏框架中,Three.js、Babylon.js和Turbulenz是比较受欢迎的选择。 Three.js是一个广泛应用并且功能强大的JavaScript 3D库,可以创建简单的3D动画到创建交互的3D游戏。 Babylon.js是David Catuhe对3D游戏引擎热爱的结果,是最好的Ja…...
浅谈一些生命周期
vue2生命周期 beforeCreate :实例创建之初 created:组件已经创建完成 beforeMount:组件挂载之前 mounted:组件挂载之后 beforeUpdate:数据发生变化 更新之前 undated:数据发生之后 beforeDestroy :实…...

JavaScript基础(25)_dom查询练习(二)
<!DOCTYPE html> <html lang"zh"> <head><meta charset"UTF-8"><title>dom查询练习二</title><link rel"stylesheet" href"../browser_default_style/reset.css"><style>form {margi…...

【React系列】React生命周期、setState深入理解、 shouldComponentUpdate和PureComponent性能优化、脚手架
本文来自#React系列教程:https://mp.weixin.qq.com/mp/appmsgalbum?__bizMzg5MDAzNzkwNA&actiongetalbum&album_id1566025152667107329) 一. 生命周期 1.1. 认识生命周期 很多的事物都有从创建到销毁的整个过程,这个过程称之为是生命周期&…...

一文初步了解slam技术
本文初步介绍slam技术,主要是slam技术的概述,涉及技术原理、应用场景、分类、以及各自优缺点,和slam技术的未来展望。 🎬个人简介:一个全栈工程师的升级之路! 📋个人专栏:slam精进之…...

滑动窗口协议仿真(2024)
1.题目描述 滑动窗口协议以基于分组的数据传输协议为特征,该协议适用于在数据链路层以及传输层中对按 顺序传送分组的可靠性要求较高的环境。在长管道传输过程(特别是无线环境)中,相应的滑动窗口 协议可实现高效的重传恢复。附录 …...
uniapp上传文件时用到的api是什么?格式是什么?
在UniApp中,你可以使用uni.uploadFile()方法来上传文件。这是一个异步方法,用于将本地资源上传到服务器。 该方法的基本格式如下: uni.uploadFile({url: 上传接口地址,filePath: 要上传的文件路径,name: 后端接收的文件参数名,formData: {/…...

Java面试——框架篇
1、Spring框架中的单例bean是线程安全的吗? 所谓单例就是所有的请求都用一个对象来处理,而多例则指每个请求用一个新的对象来处理。 结论:线程不安全。 Spring框架中有一个Scope注解,默认的值就是singleton,单例的。一…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误
HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...

【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器
一.自适应梯度算法Adagrad概述 Adagrad(Adaptive Gradient Algorithm)是一种自适应学习率的优化算法,由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率,适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...

SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现
摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序,以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务,提供稳定高效的数据处理与业务逻辑支持;利用 uniapp 实现跨平台前…...
HTML前端开发:JavaScript 常用事件详解
作为前端开发的核心,JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例: 1. onclick - 点击事件 当元素被单击时触发(左键点击) button.onclick function() {alert("按钮被点击了!&…...

以光量子为例,详解量子获取方式
光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学(silicon photonics)的光波导(optical waveguide)芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中,光既是波又是粒子。光子本…...
jmeter聚合报告中参数详解
sample、average、min、max、90%line、95%line,99%line、Error错误率、吞吐量Thoughput、KB/sec每秒传输的数据量 sample(样本数) 表示测试中发送的请求数量,即测试执行了多少次请求。 单位,以个或者次数表示。 示例:…...

pikachu靶场通关笔记19 SQL注入02-字符型注入(GET)
目录 一、SQL注入 二、字符型SQL注入 三、字符型注入与数字型注入 四、源码分析 五、渗透实战 1、渗透准备 2、SQL注入探测 (1)输入单引号 (2)万能注入语句 3、获取回显列orderby 4、获取数据库名database 5、获取表名…...

协议转换利器,profinet转ethercat网关的两大派系,各有千秋
随着工业以太网的发展,其高效、便捷、协议开放、易于冗余等诸多优点,被越来越多的工业现场所采用。西门子SIMATIC S7-1200/1500系列PLC集成有Profinet接口,具有实时性、开放性,使用TCP/IP和IT标准,符合基于工业以太网的…...

MySQL的pymysql操作
本章是MySQL的最后一章,MySQL到此完结,下一站Hadoop!!! 这章很简单,完整代码在最后,详细讲解之前python课程里面也有,感兴趣的可以往前找一下 一、查询操作 我们需要打开pycharm …...
Vue3中的computer和watch
computed的写法 在页面中 <div>{{ calcNumber }}</div>script中 写法1 常用 import { computed, ref } from vue; let price ref(100);const priceAdd () > { //函数方法 price 1price.value ; }//计算属性 let calcNumber computed(() > {return ${p…...