tartarus's bolg tartarus's bolg
  • Linux and Unix Guide
  • CMake
  • gcc
  • gdb
  • bash
  • GNU Make
  • DDCA-ETH
  • CS106L
  • CS144
  • NJU PA
  • NJU OS(jyy)
  • C
  • C++
  • Python
  • reveal-md
  • LaTex
  • Paper Reading
  • TBD
  • Linux and Unix Guide
  • CMake
  • gcc
  • gdb
  • bash
  • GNU Make
  • DDCA-ETH
  • CS106L
  • CS144
  • NJU PA
  • NJU OS(jyy)
  • C
  • C++
  • Python
  • reveal-md
  • LaTex
  • Paper Reading
  • TBD
  • pdb

  • make

  • cmake

  • Linux and Unix

    • Linux Tool介绍
    • Useful Linux Tool
    • regular-expression
    • Basic-Shell-Script
    • Using-Structured-Commands
    • More-Structured-Commands
    • Handling-User-Input
    • Presenting-Data
    • Script-Control
      • Handling Signals
        • Interrupting a process
        • Pausing a process
        • Trapping signals
        • Trapping a script exit
        • Modifying or removing a trap
      • Running Scripts in Background Mode
      • Running multiple background jobs
      • Running Scripts without a Hang-up
      • Controlling the Job
        • Viewing jobs
        • Restarting stopped job
      • Being Nice
        • Using the nice command
      • Using the renice command
      • Running like Clockwork
        • Scheduling a job using the at command
        • Understanding the at command format
      • Retrieving job output
        • Listing pending jobs
      • Removing jobs
        • Scheduling regular scripts
        • Building the cron table
      • Looking at the anacron program
      • Starting scripts with a new shell
  • Basic_Software
  • Linux and Unix
tartarus
2023-06-02
目录

Script-Control

本章内容:

Handling Signals
Running Scripts in Background Mode
Running Scripts without a Hang-Up
Controlling the Job
Being Nice Running Like Clockwork

目前为止,单位时间内我们学习到的脚本运行的方法是直接在命令行中运行,但是其实脚本还有其他的运行方式。

# Handling Signals

在 Linux 中使用信号来控制 (stop, start, and kill) 进程。

常见的控制信号有:

Signal Value Description
1 SIGHUP (关闭 terminal 时发送) Hangs up the process
2 SIGINT( CTRL + C ) Interrupts the process
20 SIGTSTP( CTRL + Z ) Stops or pauses the process, but doesn't terminate

# Interrupting a process

在 shell 中使用 CTRL + C 向运行在当前 shell 中的所有进程发送 SIGINT 信号,终止 (terminating) 进程运行。

$ sleep 70
^C
$
1
2
3

# Pausing a process

在 shell 中使用 CTRL + Z 向运行在当前 shell 中的所有进程发送 SIGTSTP 信号,停止 (Stopping) 所有进程运行,之后还能再恢复运行。

$ sleep 70
^Z
[1]+  Stopped                 sleep 70
$
1
2
3
4

在方括号总的 1 表示工作号 (job number),可以使用 jobs 命令查看当前 shell 中的工作。
shell 会将所有运行在当前 shell 中的每一个进程 (process) 都视作一个工作 (job)。
每个工作都有一个工作号。 第一个在 shell 中运行的进程工作号为 1,第二个为 2,以此类推。

如果一个 shell 中有停止运行的工作,那么使用 exit 退出 shell 时会产生警告⚠️,提示用户当前 shell 中有没有完成的工作。此时如果用户需要退出,可以在使用一次 exit 命令即可退出。

$ sleep 70
^Z
[1]+  Stopped                 sleep 70
$ exit
exit
There are stopped jobs.
$ exit
exit
1
2
3
4
5
6
7
8

使用 ps -l 命令查看当前进程中停止的工作 (stopped job),然后使用 kill -9 命令根据 stopped job 的 PID 来停止运行:

tartarus@tartarus:/tmp$ sleep 50
^Z
[1]+  Stopped                 sleep 50
tartarus@tartarus:/tmp$ ps -l
F S   UID     PID    PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
0 T  1000  229388  229340  0  80   0 -  4179 do_sig pts/5    00:00:00 sleep
...

tartarus@tartarus:/tmp$ kill -9 229388
tartarus@tartarus:/tmp$ ls
members.csv  script.sh ...
[1]+  Killed                  sleep 50
1
2
3
4
5
6
7
8
9
10
11
12

在一些 shell 中, kill 后不会立即显示被 kill 的进程的消息,会在下次出现 command prompt 的时候显示 (如上图所示是在 bash 中运行的结果)。

而一些 shell 中会立即显示 (如下图所示是在 zsh 中运行的结果):

tartarus@tartarus:/tmp$ sleep 50
^Z
[1]+  Stopped                 sleep 50
tartarus@tartarus:/tmp$ ps -l
F S   UID     PID    PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
0 T  1000  229388  229340  0  80   0 -  4179 do_sig pts/5    00:00:00 sleep
...

tartarus@tartarus:/tmp$ kill -9 229388
[1]+  Killed                  sleep 50
1
2
3
4
5
6
7
8
9
10

# Trapping signals

在运行脚本时,有时不希望运行的脚本被某些信号终止或暂停,这时可以使用 trap 命令捕获型号。

命令格式:

trap commands signals
1
  • signals: 可以是 Linux 中的指定的信号名,或者是信号名对应的数字标识。
  • commands: 是捕获信号后执行的命令。

使用举例:

$ cat script.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 5 ] 
do 
  echo "Loop #$count" 
  sleep 1 
  count=$[ $count + 1 ] 
done 
#
echo

$ ./script.sh 
This is a test script.
Loop #1
Loop #2
^C Sorry! I have trapped Ctrl-C
Loop #3
Loop #4
^C Sorry! I have trapped Ctrl-C
Loop #5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

提示

如果只想单纯的捕获某个信号,而不在捕获后执行任何命令,可以将 commands 字段设置为 "" :

trap "" SIGINT
1

# Trapping a script exit

trap 命令除了可以捕获信号外, 还可以捕获脚本的退出码,使得可以在脚本退出之前做一些必要的工作 (类似于 CPP 中的 destructor,在析构一个对象时,释放内存前做一些事情)。
举例:

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

$ ./script.sh
Loop #1
Loop #2
Loop #3
Loop #4
Loop #5
Goodbye...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

提示

使用 CTRL+C 来退出,脚本也会在终止前调用捕获 EXIT 信号的命令。

$ cat script.sh
#!/bin/bash 
#Testing exit trapping 
#
trap "echo Goodbye..." EXIT 
#
count=1 
while [ $count -le 5 ] 
do 
  echo "Loop #$count"
  sleep 1 
  count=$[ $count + 1 ] 
done #
exit%                                                                                                                                                      
$ ./script.sh
Loop #1
Loop #2
Loop #3
^CGoodbye...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# Modifying or removing a trap

  • 脚本中捕获型号后使用的处理命令可以多次修改:
$ cat script.sh
#!/bin/bash 
#Modifying a set trap 
#
trap "echo ' Sorry...Ctrl-C is trapped.'" SIGINT 
#
count=1 
while [ $count -le 3 ] 
do 
  echo "Loop #$count" 
  sleep 1 
  count=$[ $count + 1 ] 
done 
#
trap "echo ' I have modified the trap!'" SIGINT 
#
count=1 
while [ $count -le 3 ]
do
  echo "Second Loop #$count" 
  sleep 1 
  count=$[ $count + 1 ] 
done 
#
exit

$ ./script.sh
Loop #1
^C Sorry...Ctrl-C is trapped.
Loop #2
Loop #3
Second Loop #1
^C I have modified the trap!
Second Loop #2
Second Loop #3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
  • 可以使用下面的格式删除 trap ,使得信号恢复默认的处理方式
trap -- signals
1

举例:

$ cat script.sh
#!/bin/bash 
#Modifying a set trap 
#
trap "echo ' Sorry...Ctrl-C is trapped.'" SIGINT 
#
count=1 
while [ $count -le 3 ] 
do 
  echo "Loop #$count" 
  sleep 1 
  count=$[ $count + 1 ] 
done 
#
trap -- SIGINT 
echo "The trap is now removed." 
#
count=1 
while [ $count -le 3 ] 
do 
  echo "Second Loop #$count" 
  sleep 1 
  count=$[ $count + 1 ] 
done 
#
exit

$ ./script.sh
Loop #1
Loop #2
^C Sorry...Ctrl-C is trapped.
Loop #3
The trap is now removed.
Second Loop #1
Second Loop #2
^C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

提示

trap -p 命令可以列出当前使用 trap 的信号。

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

$ ./script.sh
Loop #1
trap -- 'echo '\'' Sorry...Ctrl-C is trapped.'\''' SIGINT
Loop #2
trap -- 'echo '\'' Sorry...Ctrl-C is trapped.'\''' SIGINT
Loop #3
trap -- 'echo '\'' Sorry...Ctrl-C is trapped.'\''' SIGINT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# Running Scripts in Background Mode

如果需要一个命令或者脚本运行到后台,直接在其后面加 ampersand symbol (&):

$ cat script.sh 
#!/bin/bash 
#Modifying a set trap 
#
trap "echo ' Sorry...Ctrl-C is trapped.'" SIGINT 
#
count=1 
while [ $count -le 3 ] 
do 
  echo "Loop #$count" 
  sleep 1 
  count=$[ $count + 1 ] 
done tartarus@tartarus:/tmp$ ./script.sh &
[1] 232731
$ Loop #1
Loop #2
Loop #3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

执行时,shell 中打印的 [1] 232731 表示 job number 为 1,PID 为 232731.

注意

运行在后台的进程仍然使用当前的标准输出流和标准错误流,这会使得 command line prompt 和后台命令的输出混在一起。 所以最好对命令的标准输出和标准错误输出进行重定向。 我一般使用 tmux 让程序在后台运行。

# Running multiple background jobs

也可以让多个工作同时在后台运行 (例子中的程序都是打印一句话,然后 sleep):

$ ./testAscript.sh& 
& [1] 2753 
$ This is Test Script #1. 
$ ./testBscript.sh &
& [2] 2755 
$ This is Test Script #2. 
$ ./testCscript.sh &
& [3] 2757 
$ And... another Test script. 
$ ./testDscript.sh &
& [4] 2759 
$ Then...there was one more Test script.
1
2
3
4
5
6
7
8
9
10
11
12

使用 ps 命令查看这些进程:

$ ps
PID TTY TIME CMD 
1509 pts/0 00:00:00 bash 
2753 pts/0 00:00:00 testAscript.sh 
2754 pts/0 00:00:00 sleep 
2755 pts/0 00:00:00 testBscript.sh 
2756 pts/0 00:00:00 sleep 
2757 pts/0 00:00:00 testCscript.sh 
2758 pts/0 00:00:00 sleep 
2759 pts/0 00:00:00 testDscript.sh 
2760 pts/0 00:00:00 sleep 
2761 pts/0 00:00:00 ps 
1
2
3
4
5
6
7
8
9
10
11
12

注意

上面例子中在后台运行的进程都是在 terminal session (pts/0) 中运行,如果 terminal 被关闭,所有的后台运行的进程都会被关闭。下节将讲述解决方法,或者使用 tmux 。

# Running Scripts without a Hang-up

当关闭 terminal 时,会向 shell 中的所有进程发送 SIGHUP 信号,挂断所有的进程。使用 nohup command 命令,可以使得 command 对应的进程即使在 terminal 结束以后,还是继续正常运行。

命令格式:

nohup command
1

使用举例:

$ nohup ./testAscript.sh &
[1] 81080
$ appending output to nohup.out
$ cat nohup.out 
This is Test Script #1.
1
2
3
4
5

(标准输出和标准错误输出都会被放到文件 nohup.out 中)

[1] 是 shell 分配的工作号, 81080 是 OS 分配的进程号。

# Controlling the Job

什么是 job control ?
starting, stopping, killing, and resuming jobs 的方法。

# Viewing jobs

使用 jobs 命令查看当前 shell 中的工作进程的情况。

使用举例:

  • 第一次脚本执行使用 CTRL+Z 命令发送信号 SIGTSTP 到进程中,暂停进程执行。
  • 第二次脚本执行在后台运行,并把标准输出重定向到文件中。
  • jobs 命令输出的结果中:
    • + 表示该工作为默认工作,不需要指定工作号 (job numbers),会被任何的 job 控制命令 (control command) 执行。
    • - 表示该工作将成为默认工作,如果 + 的工作执行结束。
  • 使用 jobs -l 展示所有工作的 PID
  • 如果需要结束 job,使用 kill -9 命令发送 SIGKILL (9) 到 job。
$ cat script.sh
#!/bin/bash 
#Testing job control 
#
echo "Script Process ID: $$" 
#
count=1 
while [ $count -le 5 ] 
do 
  echo "Loop #$count" 
  sleep 10 
  count=$[ $count + 1 ] 
done 
#
echo "End of script..." 
exit

$ ./script.sh
Script Process ID: 99280
Loop #1
^Z
[1]  + 99280 suspended  ./script.sh

$ ./script.sh > jobcontrol.out &
[2] 99356

$ jobs -l
[1]  + 99280 suspended  ./script.sh
[2]  - 99356 running    ./script.sh > jobcontrol.out

$ kill -9 99280
[1]  + 99280 killed     ./script.sh

$ jobs -l
[2]  + 99356 running    ./script.sh > jobcontrol.out

$ kill -9 99356
[2]  + 99356 killed     ./script.sh > jobcontrol.out

$ jobs -l
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

# Restarting stopped job

使用 bg 和 fg 将暂停的 job 分别调度到 background 和 foreground 继续运行。
(bash 中的使用方法,其他 shell 中不一定适用)

$ ./script.sh > /dev/null
^Z
[1]+  Stopped                 ./script.sh > /dev/null
$ ./script.sh > /dev/null
^Z
[2]+  Stopped                 ./script.sh > /dev/null
$ obs

Command 'obs' not found, but can be installed with:

sudo apt install obs-studio

$ jobs
[1]-  Stopped                 ./script.sh > /dev/null
[2]+  Stopped                 ./script.sh > /dev/null
$ fg 1
./script.sh > /dev/null
^Z
[1]+  Stopped                 ./script.sh > /dev/null
$ jobs
[1]+  Stopped                 ./script.sh > /dev/null
[2]-  Stopped                 ./script.sh > /dev/null
$ bg 2
[2]- ./script.sh > /dev/null &
$
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

提示

默认工作可以直接调用 fg 或者 bg 命令。非默认工作需要使用 fg 和 bg 命令时需要加上工作号 ( zsh 中工作号前需要加入 % )。

# Being Nice

调度优先级 (scheduling priority) 也被称为 nice value。调度优先级是从 - 20 (最高的优先级)~+19 (最低的优先级) 之间的数。

提示

优先级越高,单位时间内占用的 CPU 周期越多。

可以使用 nice 命令改变 shell 中命令的优先级。

# Using the nice command

默认情况下,shell 中执行的所有命令的优先级都是 0。

可以使用 nice 命令降低或者升高优先级并执行命令 command :

nice -n nums command
1

(其中 nums 为 - 20~19 之间的数。)

举例:降低命令的优先级

$ cat script.sh 
#!/bin/bash 
#Testing job control 
#
echo "Script Process ID: $$" 
#
count=1 
while [ $count -le 5 ] 
do 
  echo "Loop #$count" 
  sleep 10 
  count=$[ $count + 1 ] 
done 
#
echo "End of script..." 

$ nice -n 10  ./script.sh > /dev/null &
[1] 359050

$ jobs
[1]+  Running                 nice -n 10 ./script.sh > /dev/null &

$ ps -p 359050 -o pid,ppid,ni,cmd # 其中NI表示nice value,即优先级
    PID    PPID  NI CMD
 359050  358320  10 /bin/bash ./script.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

举例:增高命令的优先级到负值

$ nice -n -5 ./script.sh > /dev/null &
[1] 359566
$ nice: cannot set niceness: Permission denied
1
2
3

提示

nice 命令阻止普通用户增加命令执行的优先级,只有 root 用户有增加优先级到负值的权限。

# Using the renice command

使用 renice 通过工作的 PID 号来改变正在执行的命令的优先级。

举例:

$ cat script.sh 
#!/bin/bash 
#Testing job control 
#
echo "Script Process ID: $$" 
#
count=1 
while [ $count -le 5 ] 
do 
  echo "Loop #$count" 
  sleep 10 
  count=$[ $count + 1 ] 
done 
#
echo "End of script..." 
exit[2]+  Done                    sudo nice -n -5 ./script.sh > /dev/null

$ ./script.sh > /dev/null&
[1] 360058

$ ps -p 360058 -o pid,ppid,ni,cmd # NI表示nice value,即优先级
    PID    PPID  NI CMD
 360058  358320   0 /bin/bash ./script.sh

$ renice -n 10 -p 360058
360058 (process ID) old priority 0, new priority 10

$ ps -p 360058 -o pid,ppid,ni,cmd
    PID    PPID  NI CMD
 360058  358320  10 /bin/bash ./script.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

# Running like Clockwork

(clockwork: 机械⚙️)

使用 at , cron , anacron 命令,可以在未来的某个时间执行某条命令。

# Scheduling a job using the at command

at 命令可以用来指定未来某一时刻做某件事。

at 命令会将用户指定的工作和工作时间放入文件夹 ( /var/spool/at or /var/spool/cron/atjobs ) 中, atd (at daemon) 命令会检查文件夹 ( /var/spool/at or /var/spool/cron/atjobs ) 下是否有工作任务,以及工作任务的执行时间 (通常每间隔 60s 检查一次);如果工作任务的执行时间和当前时间相同,就执行相应的工作。

at 命令会将工作放入不同的优先级队列中,A-Za-z。其中 A 具有最高的优先级,z 具有最低的优先级。(可以使用 -q 指定优先级)
(按照字母 ascii 排列,越大的值具有越低的优先级)

# Understanding the at command format

at 命令的格式:

at [-f filename ] time
1

默认情况下, at 命令从 STDIN 输入 (类似于 cat> file.txt 的用法),以 CTLR + D 作为结尾。

$ at now + 1 minutes
warning: commands will be executed using /bin/sh
at> echo "hello worlds" > output.txt
at> <EOT>
job 6 at Fri Jun  9 22:04:00 2023

$ cat output.txt # 还没有一分钟时读取output.txt
cat: output.txt: No such file or directory

$ cat output.txt # 过一分钟后
hello worlds
1
2
3
4
5
6
7
8
9
10
11

也可以从文件 (脚本) 中读取命令

at -f filename time
1

时间有很多形式:

  1. 标准的 24h 制: 10:15
  2. 12h 制: 10:15PM
  3. 特定的时间名: now , noon , midnight
  4. 标准时间格式: MMDDYY , MM/DD/YY , or DD.MM.YY
  5. 在某个时间点增加一段时间: Now + 25 minutes , 10:15 + 7 days

# Retrieving job output

使用 at 将要执行的命令加入工作队列后,工作在指定时间开始执行,并将 STDERR 和 STDOUT 通过 email 发送给创建工作的用户。

但是一些 Linux Distribution 中没有邮件系统。所以可以统一采用重定向的方式对输出进行处理:

$ cat script.sh
#!/bin/bash 
# Trying out the at command redirecting output 
#
outfile=tryat.out 
#
echo "This script ran at $(date +%B%d,%T)"> $outfile 
echo>> $outfile 
echo "This script is using the $SHELL shell.">> $outfile 
echo>> $outfile 
sleep 5 
echo "This is the script's end.">> $outfile 
#
exit

$ cat tryat.out
cat: tryat.out: No such file or directory

$ at -f script.sh now
warning: commands will be executed using /bin/sh
job 8 at Fri Jun  9 22:59:00 2023

$ cat tryat.out
This script ran at June09,22:59:15

This script is using the  shell.

This is the script's end.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

可以使用 -M 选项忽略工作运行时产生的所有输出 ( STDERR and STDOUT ):

$ cat script.sh
#!/bin/bash 
# Trying out the at command redirecting output 
#
outfile=tryat.out 
#
echo "This script ran at $(date +%B%d,%T)"
echo
echo "This script is using the $SHELL shell."
echo
sleep 5 
echo "This is the script's end."
#
exit

$ at -M -f script.sh now
warning: commands will be executed using /bin/sh
job 10 at Fri Jun  9 23:04:00 2023
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# Listing pending jobs

使用 atq 命令,可以查看所有延时执行的工作。

举例:

$ at -M -f script.sh tomorrow
warning: commands will be executed using /bin/sh
job 11 at Sun Jun 11 02:19:00 2023

$ at -M -f script.sh teatime
warning: commands will be executed using /bin/sh
job 12 at Sat Jun 10 16:00:00 2023

$ at -M -f script.sh 20:40
warning: commands will be executed using /bin/sh
job 13 at Sat Jun 10 20:40:00 2023

$ at -M -f script.sh now + 1hour
warning: commands will be executed using /bin/sh
job 14 at Sat Jun 10 03:19:00 2023

$ atq # 其中每一列表示: 工作号 执行时间 优先级 用户
13      Sat Jun 10 20:40:00 2023 a tartarus
12      Sat Jun 10 16:00:00 2023 a tartarus
11      Sun Jun 11 02:19:00 2023 a tartarus
14      Sat Jun 10 03:19:00 2023 a tartarus
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# Removing jobs

使用 atrm job_number 可以移除延时的工作:

$ atq
13      Sat Jun 10 20:40:00 2023 a tartarus
12      Sat Jun 10 16:00:00 2023 a tartarus
11      Sun Jun 11 02:19:00 2023 a tartarus
14      Sat Jun 10 03:19:00 2023 a tartarus
$ atrm 11
$ atq
13      Sat Jun 10 20:40:00 2023 a tartarus
12      Sat Jun 10 16:00:00 2023 a tartarus
14      Sat Jun 10 03:19:00 2023 a tartarus
1
2
3
4
5
6
7
8
9
10

提示

当前用户只能移除当前用户创建的延时工作,其他用户创建的工作,当前用户不能移除。

# Scheduling regular scripts

at 命令只能在未来某一个时间点执行工作,如果想要使得每天 / 每周都执行某个工作,就需要使用 cron 命令 (cron is abbreviate of command run on)。

cron 命令通过检查 cron table 来实现在未来重复的执行某一工作。

cron table 的格式为:

minuteofhour hourofday dayofmonth month dayofweek command
1

minuteofhour: 一个小时的第几分钟 (00~59)
hourofday: 一天的第几小时 (0~23)
dayofmonth: 月号 (1~31)
month: 第几个月 (1~12)
dayofweek: 每周的第几天 (1~7)

举例:
每天的 10:15 执行 command
15 10 * * * command

每周一的 16:15 执行 command
15 16 * * 1 command

每个月 1 号的 12:00 执行 command
00 12 1 * * command

每个月最后一天 12:00 执行 command
00 12 28-31 * * if [ "$(date +%d -d tomorrow)" = 01 ] ; then command ; fi

注意

执行脚本或者没有在环境变量路径中命令时,应指定 fullpath.

15 10 * * * /home/christine/backup.sh> backup.out

# Building the cron table

crontab -l 命令列出当前所有存在的 cron table :

$ crontab -l
crontab: no crontab for tartarus
1
2

crontab -e 命令编辑 cron table .

使用 select-editor 选择编辑 cron table 使用的编辑器。

另外还可以使用 cron 预先定义好的文件夹:

这里有四个文件夹,它们中的命令回每天 / 每小时 / 每个月 / 每个周执行。

❯ ls /etc/cron.*ly
/etc/cron.daily:
0anacron  apt-compat    cracklib-runtime  google-chrome  logrotate  popularity-contest
[...]

/etc/cron.hourly:
[...]

/etc/cron.monthly:
[...]

/etc/cron.weekly:
0anacron  man-db  update-notifier-common
[...]
1
2
3
4
5
6
7
8
9
10
11
12
13
14

提示

如果希望一个脚本大概的在上面这些时间点执行,可以选择将脚本直接复制到其中的某一个文件夹。

# Looking at the anacron program

cron 存在的问题是,你的 Linux 环境必须是 24*7 运行的,而且如果系统关机后,如果有工作在关机时间段应该执行,之后在开机后也不会执行。 (missed job)

anacron (anachronistic (过时的) command run on) 会使用 timestamp,查看工作上次执行的时间。

  • anacron 只能用来执行 cron 文件夹中的每日 / 每月 / 每年。
    $ ls /var/spool/anacron
    cron.daily  cron.monthly  cron.weekly
    
    1
    2
  • /var/spool/anacron 中存放了 timestamp,用来表示上次命令执行的时间。
    $ sudo cat cron.daily
    20230609
    
    1
    2
  • anacron 有自己的 table
    $ cat /etc/anacrontab
    # /etc/anacrontab: configuration file for anacron
    
    # See anacron(8) and anacrontab(5) for details.
    
    SHELL=/bin/sh
    PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
    HOME=/root
    LOGNAME=root
    
    # These replace cron's entries
    1       5       cron.daily      run-parts --report /etc/cron.daily
    7       10      cron.weekly     run-parts --report /etc/cron.weekly
    @monthly        15      cron.monthly    run-parts --report /etc/cron.monthly
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    • anacron 表格中表项的格式为:
      period delay identifier command
      • period: 表示工作多久需要被执行一次
      • delay: 表示系统启动多久后,应该执行遗失的工作 (missed job)

# Starting scripts with a new shell

at , cron 和 anacron 都是在指定的时间运行脚本,但是有时我们可能需要在新的 shell 创建时就运行脚本。

当新的 bash shell 被创建时, Bash shell 会运行 .bashrc 。
测试方法:

$ echo " echo \"i'm in new shell\" " >> .bashrc
$ bash
echo i'm in new shell
1
2
3
上次更新: 12/27/2023, 8:55:47 AM
Presenting-Data

← Presenting-Data

Theme by Vdoing | Copyright © 2023-2023 tartarus | CC BY-NC-SA 4.0
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式