Linux 运行和控制 shell 脚本

脚本控制

对于 shell 脚本,我们最简单的操作是直接运行它。除此之外,我们还可以通过向运行中的脚本发送信号、修改脚本的优先级以及切换运行模式等等途径控制脚本。

一、处理信号

Linux 利用信号与运行在系统中的进程进行通信。Linux 系统和应用程序可以生成超过30个信号。其中,最常见的 Linux 系统信号:

信号名称描述
1HUP挂起
2INT中断
3QUIT结束运行
9KILL无条件终止
11SEGV段错误
15TERM尽可能终止
17STOP无条件终止运行,到不终止
18TSTP停止或暂停,但继续在后台运行
19CONT在STOP或TSTP之后恢复执行

默认情况下,bash shell 会忽略收到的任何 QUIT(3)和 ERM(15),这样可以避免交互式 shell 不会被意外终止。但是 bash shell 会处理收到的 HUP(1)和 INT(2)信号。

1 生成信号

bash shell 允许用键盘上的组合键生成两种基本的Linux信号。

1.1 中断进程

Ctrl+C 组合键会生成 INT 信号,并将其发送给当前 shell 中运行的所有进程。

zzz@ubuntu:~$ sleep 100
^C
zzz@ubuntu:~$
1.2 暂停进程

有时需要将运行中的进程暂停,继续保存在内存中,而不是彻底中断。

zzz@ubuntu:~$ sleep 100
^Z
[1]+  已停止               sleep 100
zzz@ubuntu:~$ ps
F S   UID     PID    PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
0 S  1000    1688    1687  0  80   0 -  3503 do_wai pts/0    00:00:00 bash
0 T  1000    1818    1688  0  80   0 -  2790 do_sig pts/0    00:00:00 sleep
0 R  1000    1822    1688  0  80   0 -  3627 -      pts/0    00:00:00 ps
zzz@ubuntu:~$ exit
注销
有停止的任务。
zzz@ubuntu:~$

在返回的信息中,方括号中的数字是shell分配的作业号。可以使用ps命令查看已停止的作业,已停止的作用的状态显示为 T。当 shell 会话中存在一个已停止的作业时,exit 命令将会返回提示信息。

2 捕获信号

trap 命令可以指定捕获到特定命令后要执行的命令。trap 命令的格式:

trap commands signals

在 trap 命令行上,可以列出想要 shell 执行的命令,以及一组用空格分开的待捕获的信号,可以用信号名或数字。

zzz@ubuntu:~/my_learning$ cat test7.sh 
#!/bin/bash

# 捕获信号
trap "echo 'Sorry! script running...'" SIGINT

echo "Start running..."

count=1
while [ $count -le 10 ]
do
    echo "Loop $count"
    sleep 2
    count=$[ $count + 1 ]

done

# 修改信号捕获
trap "echo 'modified trap'" SIGINT

sleep 10

# 取消信号捕获
echo "delete trap"
trap -- SIGINT

sleep 10

zzz@ubuntu:~/my_learning$ ./test7.sh 
Start running...
Loop 1
Loop 2
^CSorry! script running...
Loop 3
Loop 4
^CSorry! script running...
Loop 5
Loop 6
Loop 7
^CSorry! script running...
Loop 8
Loop 9
Loop 10
^Cmodified trap
delete trap
^C
zzz@ubuntu:~/my_learning$

二、后台模式运行脚本

有时一些脚本可能会执行很长时间,这样在运行期间终端就不能再处理其它命令。此时,我们需要将脚本放到后台运行,此时进程将不再运行在终端显示器上,不会和终端会话的 STDIN、STDOUT 和 STDERR 关联。

1. 在后台运行脚本

要以后台模式运行 shell 脚本,只要在命令后加 & 符就可以。当 & 放到命令后时,它会将命令和 bash shell 分离开,将命令作为系统中一个独立的后台进程运行。

zzz@ubuntu:~/my_learning$ sleep 10 &
[3] 2151
zzz@ubuntu:~/my_learning$

显示的第一行,方括号中的数字是 shell 分配给后台进程的作业号。下一个数是 Linux 系统分配给进程的进程ID。

2. 运行多个后台作业

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

zzz@ubuntu:~/my_learning$ sleep  20 &
[3] 2156
zzz@ubuntu:~/my_learning$ sleep 15 &
[4] 2157
zzz@ubuntu:~/my_learning$ ps
    PID TTY          TIME CMD
   1688 pts/0    00:00:00 bash
   1818 pts/0    00:00:00 sleep
   1915 pts/0    00:00:00 test7.sh
   1917 pts/0    00:00:00 sleep
   2156 pts/0    00:00:00 sleep
   2157 pts/0    00:00:00 sleep
   2158 pts/0    00:00:00 ps
zzz@ubuntu:~/my_learning$

3. 在非控制台下运行脚本

使用 & 将进程放入后台,如果当前终端退出后,后台运行的进程也将随之退出。如果想要在终端退出后,脚本依然可以以后台模式运行直到结束,可以使用 nohup 命令。
nohup 命令运行了另外一个命令来阻断所有发送给该进程的 HUP 信号。这会在退出终端会话时阻止进程退出,且进程与 STDOUT 和 STDERR 也不再关联,而是会将输出重定向到一个名为 nohup.out 的文件中。nohup 命令的格式如下:

nohup command &
zzz@ubuntu:~/my_learning$ nohup sleep 10 &
[3] 2174
zzz@ubuntu:~/my_learning$ nohup: 忽略输入并把输出追加到'nohup.out'

三、作业控制

在使用组合键停止作业后,也可以选择进一步终止或重启。启动、停止、终止以及恢复作业的这些功能统称为作业控制。作业控制可以完全控制 shell 环境中所有进程的运行方式。

1. 查看作业

作业控制的关键命令是 jobs 命令。jobs 命令允许查看 shell 当前正在处理的作业。jobs 命令格式和不同的命令行参数:

jobs options
参数描述
-l列出进程的PID以及作业号
-n只列出上次 shell 发出的通知后改变了状态的作业
-p只列出作业的PID
-r只 列出运行中的作业
-s只列出已停止的作业
zzz@ubuntu:~/my_learning$ ./test7.sh > test7a.out &
[3] 2223
zzz@ubuntu:~/my_learning$ ./test7.sh > test7b.out &
[4] 2228
zzz@ubuntu:~/my_learning$ ./test7.sh > test7c.out &
[5] 2233
zzz@ubuntu:~/my_learning$ jobs -l
[1]-  1818 停止                  sleep 100  (工作目录: ~)
[2]+  1915 停止                  ./test7.sh
[3]   2223 运行中               ./test7.sh > test7a.out &
[4]   2228 运行中               ./test7.sh > test7b.out &
[5]   2233 运行中               ./test7.sh > test7c.out &
zzz@ubuntu:~/my_learning$ kill 2223
zzz@ubuntu:~/my_learning$ jobs -l
[1]-  1818 停止                  sleep 100  (工作目录: ~)
[2]+  1915 停止                  ./test7.sh
[3]   2223 已终止               ./test7.sh > test7a.out
[4]   2228 运行中               ./test7.sh > test7b.out &
[5]   2233 运行中               ./test7.sh > test7c.out &
zzz@ubuntu:~/my_learning$ kill 2228
zzz@ubuntu:~/my_learning$ jobs -l
[1]-  1818 停止                  sleep 100  (工作目录: ~)
[2]+  1915 停止                  ./test7.sh
[4]   2228 已终止               ./test7.sh > test7b.out
[5]   2233 运行中               ./test7.sh > test7c.out &
zzz@ubuntu:~/my_learning$

加号表示对应的作业被当作默认作业,在未指定作业号时,该作业会被当成被控制对象。

2. 重启停止的作业

在 bash 作业控制中,可以将以停止的作业作为后台进程或前台进程重启。前台进程会接管当前工作的终端。
以后台模式重启
要以后台模式重启一个作业,可用 bg 命令加上作业号:

zzz@ubuntu:~/my_learning$ ./test7.sh > test7a.out
^Z
[3]+  已停止               ./test7.sh > test7a.out
zzz@ubuntu:~/my_learning$ ./test7.sh > test7b.out
^Z
[4]+  已停止               ./test7.sh > test7b.out
zzz@ubuntu:~/my_learning$ jobs -l
[1]   1818 停止                  sleep 100  (工作目录: ~)
[2]   1915 停止                  ./test7.sh
[3]-  2345 停止                  ./test7.sh > test7a.out
[4]+  2348 停止                  ./test7.sh > test7b.out
zzz@ubuntu:~/my_learning$ bg 4
[4]+ ./test7.sh > test7b.out &
zzz@ubuntu:~/my_learning$ jobs -l
[1]   1818 停止                  sleep 100  (工作目录: ~)
[2]-  1915 停止                  ./test7.sh
[3]+  2345 停止                  ./test7.sh > test7a.out
[4]   2348 运行中               ./test7.sh > test7b.out &
zzz@ubuntu:~/my_learning$

以前台模式重启
要以前台模式重启作业,可以使用带有作业号的 fg 命令:

zzz@ubuntu:~/my_learning$ jobs -l
[1]   1818 停止                  sleep 100  (工作目录: ~)
[2]-  1915 停止                  ./test7.sh
[3]+  2345 停止                  ./test7.sh > test7a.out
zzz@ubuntu:~/my_learning$ fg 3
./test7.sh > test7a.out
zzz@ubuntu:~/my_learning$

四、调整谦让度

多任务系统中,内核负责将CPU时间分配给系统上运行的每个进程。调度优先级是内核分配给进程CPU时间。调度优先级是整数值(-20最高优先级~19最低优先级)。默认情况下,bash shell 以优先级 0 来启动所有进程。

1. nice 命令

nice 命令允许你设置命令启动时的调度优先级。只要使用 nice 的 -n 命令行来指定新的优先级级别。

zzz@ubuntu:~/my_learning$ nice -n 10 ./test7.sh > test7a.out &
[1] 2538
zzz@ubuntu:~/my_learning$ ps -p 2538 -o pid,ppid,ni,cmd
    PID    PPID  NI CMD
   2538    2488  10 /bin/bash ./test7.sh
zzz@ubuntu:~/my_learning$

2. renice 命令

nice 命令是在执行命令时设置优先级,如果需要对以运行的命令修改优先级,可以使用 renice 命令。

zzz@ubuntu:~/my_learning$ ./test7.sh > test7a.out &
[1] 2601
zzz@ubuntu:~/my_learning$ ps -p 2601 -o pid,ppid,ni,cmd
    PID    PPID  NI CMD
   2601    2488   0 /bin/bash ./test7.sh
zzz@ubuntu:~/my_learning$ renice -n 10 -p 2601
2601 (process ID) 旧优先级为 0,新优先级为 10
zzz@ubuntu:~/my_learning$ ps -p 2601 -o pid,ppid,ni,cmd
    PID    PPID  NI CMD
   2601    2488  10 /bin/bash ./test7.sh
zzz@ubuntu:~/my_learning$

renice 命令会自动更新当前运行进程的调度优先级。和 nice 一样,renice 命令也有一些设置:

  • 只能对属于你的进程执行 renice;
  • 只能通过 renice 降低进程的优先级;
  • root 用户可以通过 renice 来任意调整进程的优先级;

如果想完全控制运行进程,可以使用sudo命令或使用root 账户。

五、定时运行作业

有时,我们需要在某个预定的时间自动运行脚本。Linux 提供了多个在预选时间运行脚本的方法:at 命令和 cron 表。

1. 用 at 命令来计划执行作业

at 命令允许指定 Linux 系统何时运行脚本。at 命令会将作业提交到队列中,指定 shell 何时运行该作业。at 守护进程 atd 会以后台模式运行,检查作业队列来运行作业,大多数Linux发行版会在启动时运行该守护进程。
atd 守护进程会检查系统上的一个特殊目录(通常是 /var/spool/at)来获取 at 命令提交的作业。默认情况下,atd 守护进程会在每60s检查一下这个目录。
at 命令的基本格式:

at [-f filename] time

at 命令使用 -f 来指定读取命令的文件名,time 指定系统何时运行该作业。at 命令能够识别多种不同的时间格式:

  • 标准的小时和分钟格式,如 10:15
  • AM/PM指示符,比如 10:15
  • 特定可命名时间,比如 now、noon、midnight或者teatime

除了指定运行作业的时间,也可以通过不同的日期格式指定特定的日期:

  • 标准日期格式,如 MMDDYY、MM/DD/YY或DD.MM.YY
  • 文本日期,如 Jul 4或Dec 25,加不加年份都可以
  • 也可以指定时间增量:
    • 当前时间+25min
    • 明天10:15 PM
    • 10:15+7天

使用 at 命令提交命令到作业队列。作业队列会保存通过 at 命令提交的待处理的作业。根据不同的优先级,存在26种(a~z)不同的作业队列,字母排序越高,优先级越低,默认情况下,作业会被提交到a作业队列,可以使用-q参数指定队列字母。
删除作业
使用 atq 命令可以获得哪些作业在作业队列中等待,然后可以使用 atrm 命令删除等待的作业。

atrm 作业号

2. 安排需要定期执行的脚本

Linux 系统使用 cron 程序来安排要执行的作业。cron 程序会在后台运行并检查一个特殊的表(cron事件表),以获知已安排执行的作业。

1. cron 时间表

cron 时间表采用一个特别的格式来指定作业何时运行,其格式如下:

min hour dayofmonth month dayofweek command

cron 时间表允许使用特定值、取值范围(如0~5)或者通配符(星号)来指定条目。例如,
在每天10:15运行一个命令:

15 10 * * * command

指定每周一4:15 PM运行的命令:

15 16 * * 1 command
2. 构建 cron 时间表

每个系统用户都可以用自己的 cron 时间表来运行安排好的任务。Linux 使用 crontab 命令来处理 cron 时间表,要列出已有的 cron 时间表可以使用 -l 选项。如果要为 cron 添加条目,可以使用crontab -e 选项,该选项会打开一个编辑器。

zzz@ubuntu:~/my_learning$ crontab -l
no crontab for zzz
zzz@ubuntu:~/my_learning$ crontab -e
3. 浏览cron 目录

如果脚本对执行时间没有精确的要求,用预配置的 cron 脚本目录会更方便。有四个基本目录:cron.daily、cron.hourly、cron.weekly 和 cron.monthly。如果将脚本复制到 daily 目录,cron 就会每天执行它。

zzz@ubuntu:~/my_learning$ ls /etc/cron.*ly
/etc/cron.daily:
0anacron  apt-compat    cracklib-runtime  logrotate  popularity-contest  update-notifier-common
apport    bsdmainutils  dpkg              man-db     sysstat

/etc/cron.hourly:

/etc/cron.monthly:
0anacron

/etc/cron.weekly:
0anacron  man-db  update-notifier-common
zzz@ubuntu:~/my_learning$ 
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值