Fork me on GitHub

git 基础

git

[toc]

背景

  • 如何避免功能之间的相互干扰

  • 如果快速对线上bug进行修复并上线

  • 如何保证功能提测和上线的一致性

目标

  • 实现git普通基本操作
  • 实现git分支创建、合并和冲突解决
  • 能规范使用git用于版本控制和发布

基本概念

基本操作

diff

合并冲突

警告:运行git-merge时含有大量的未commit文件很容易让你陷入困境,这将使你在冲突中难以回退。因此非常不鼓励在使用git-merge时存在未commit的文件,建议使用git-stash命令将这些未commit文件暂存起来,并在解决冲突以后使用git stash pop把这些未commit文件还原出来

提交历史中搜索文本-git grep

要搜索提交内容(即实际的源代码行,而不是提交消息等)

1
2
3
4
5
6
7
8
9
#要搜索提交内容(即实际的源代码行,而不是提交消息等)
git grep <regexp> $(git rev-list --all)
#更新:如果遇到"参数列表太长"错误,git rev-list --all | xargs git grep 将工作
git grep <regexp> $(git rev-list --all | xargs git grep)
#如果要将搜索限制在某些子树(例如"lib/util"),则需要将其传递给rev-list子命令和grep:
git grep <regexp> $(git rev-list --all -- lib/util) -- lib/util

#在Rev1和Rev2之间的所有修订中搜索与正则表达式regexp匹配的文本:
git grep <regexp> $(git rev-list <rev1>..<rev2>)

跨所有分支搜索文本-git log

1
2
3
4
5
6
7
8
9
10
11
12
# 在所有提交历史中搜索commit message包含的文本
$ git log --grep='采购方案'
# 查看文本关联提交及每个提交具体修改情况(速度很快,在每个提交中搜索每个具体文件内容)
git log -p --all -S 'search string'
git log -p --all -G 'match regular expression'

$ git log --since=2021.10.20 --until=2021.10.25 -S 'reportPurchasingMethod' -- sql/

#在所有提交历史中搜索文本所在的提交
git rev-list --all | xargs git grep <regexp>
#然后可以使用git show获取更多信息,如作者、日期、差异
git show 6988bec26b1503d45eb0b2e8a4364afb87dde7af

分支管理

Git Flow

  • 所有在master分支上的Commit应该对应到具体的Tag

  • release分支基于develop分支创建 (记住:一旦打了release分支之后不要从develop分支上合并新的改动到release分支)

  • hotfix分支基于master分支创建,开发完后测试后,需要合并回master分支和develop分支,同时在master上打一个tag

配置

参考

Learn Git Branching可视化

excel使用技巧

excel

公式和函数

引用

引用的作用在于标识工作表上的单元格或单元格区域,并告知 Excel 在何处查找要在公式中使用的值或数据。 你可以使用引用在一个公式中使用工作表不同部分中包含的数据,或者在多个公式中使用同一个单元格的值。 还可以引用同一个工作簿中其他工作表上的单元格和其他工作簿中的数据。 引用其他工作簿中的单元格被称为链接或外部引用。

A1 引用样式

默认情况下,Excel 使用 A1 引用样式,此样式引用字母标识列(从 A 到 XFD,共 16,384 列)以及数字标识行(从 1 到 1,048,576)。 这些字母和数字被称为行号和列标。 要引用某个单元格,请输入列标,后跟行号。 例如,B2 引用列 B 和行 2 交叉处的单元格。

若要引用 用途
列 A 和行 10 交叉处的单元格 A10
在列 A 和行 10 到行 20 之间的单元格区域 A10:A20
在行 15 和列 B 到列 E 之间的单元格区域 B15:E15
行 5 中的全部单元格 5:5
行 5 到行 10 之间的全部单元格 5:10
列 H 中的全部单元格 H:H
列 H 到列 J 之间的全部单元格 H:J
列 A 到列 E 和行 10 到行 20 之间的单元格区域 A10:E20

绝对引用、相对引用和混合引用之间的区别

相对引用 公式中的相对单元格引用(如 A1)是基于包含公式和单元格引用的单元格的相对位置。 如果公式所在单元格的位置改变,引用也随之改变。 如果多行或多列地复制或填充公式,引用会自动调整。 默认情况下,新公式使用相对引用。 例如,如果将单元格 B2 中的相对引用复制或填充到单元格 B3,将自动从 =A1 调整到 =A2。

复制的公式具有相对引用

绝对引用 公式中的绝对单元格引用(如 $A$1)总是在特定位置引用单元格。 如果公式所在单元格的位置改变,绝对引用将保持不变。 如果多行或多列地复制或填充公式,绝对引用将不作调整。 默认情况下,新公式使用相对引用,因此您可能需要将它们转换为绝对引用。 例如,如果将单元格 B2 中的绝对引用复制或填充到单元格 B3,则该绝对引用在两个单元格中一样,都是 =$A$1。

复制的公式具有绝对引用

混合引用 混合引用具有绝对列和相对行或绝对行和相对列。 绝对引用列采用 $A1、$B1 等形式。 绝对引用行采用 A$1、B$1 等形式。 如果公式所在单元格的位置改变,则相对引用将改变,而绝对引用将不变。 如果多行或多列地复制或填充公式,相对引用将自动调整,而绝对引用将不作调整。 例如,如果将一个混合引用从单元格 A2 复制到 B3,它将从 =A$1 调整到 =B$1。

复制的公式具有混合引用

最常用的10个函数

日期和时间函数

workday

只计算工作日。excel 加天数 如果为周末顺延

语法

WORKDAY(start_date, days, [holidays])

WORKDAY 函数语法具有下列参数:

  • Start_date 必需。 一个代表开始日期的日期。
  • Days 必需。 start_date 之前或之后不含周末及节假日的天数。 Days 为正值将生成未来日期;为负值生成过去日期。
  • Holidays 可选。 一个可选列表,其中包含需要从工作日历中排除的一个或多个日期,例如各种省/市/自治区和国家/地区的法定假日及非法定假日。 该列表可以是包含日期的单元格区域,也可以是由代表日期的序列号所构成的数组常量。
备注
  • Microsoft Excel 可将日期存储为可用于计算的序列号。 默认情况下,1900 年 1 月 1 日的序列号是 1,而 2008 年 1 月 1 日的序列号是 39448,这是因为它距 1900 年 1 月 1 日有 39448 天。
  • 如果任一参数不是有效日期,则 WORKDAY 返回#VALUE! 错误值。
  • 如果start_date加上天生成无效日期,则 WORKDAY 返回#NUM! 错误值。
  • 如果 days 不是整数,将截尾取整。

逻辑函数

将 IF 函数与 AND、OR 以及 NOT 函数配合使用

IF 函数允许通过测试某个条件并返回该条件为 True 或 False 的结果,从而对某个值和预期值进行逻辑对比。

  • =IF(内容为 True,则执行某些操作,否则就执行其他操作)

但如果需要测试多个条件,例如我们假设所有条件都需要为 True 或 False (AND),或只有一个条件需要为 True 或 False (OR),或者如果想要检查某个条件是否不 (NOT) 符合你的条件,这时该怎么做呢? 这三个函数均可以单独使用,但它们更常见于与 IF 函数成对使用。

技术细节

将 IF 函数与 AND、OR 和 NOT 配合使用以执行条件是否为 True 或 False 的多项计算。

语法
  • IF(AND()) - IF(AND(logical1, [logical2], …), value_if_true, [value_if_false]))
  • IF(OR()) - IF(OR(logical1, [logical2], …), value_if_true, [value_if_false]))
  • IF(NOT()) - IF(NOT(logical1), value_if_true, [value_if_false]))
参数名称 说明
logical_test(必需) 要测试的条件。
value_if_true(必需) logical_test 的结果为 TRUE 时你希望返回的值。
value_if_false(可选) logical_test 的结果为 FALSE 时你希望返回的值。

下面是如何分别构造 ANDORNOT 函数的概述。 当将它们分别与 IF 语句组合使用时,应按如下方式表达:

  • AND – =IF(AND(Something is True, Something else is True), Value if True, Value if False)
  • OR – =IF(OR(Something is True, Something else is True), Value if True, Value if False)
  • NOT – =IF(NOT(Something is True), Value if True, Value if False)
示例

下面是一些常见的嵌套 IF(AND())、IF(OR()) 和 IF(NOT()) 语句的示例。 AND 和 OR 函数最多可支持 255 个单独条件,但并不建议使用多个条件,因为构建、测试和维护复杂的嵌套公式是非常难的。 NOT 函数仅采用一个条件。

下面是根据它们的逻辑写出的公式:

公式 说明
=IF(AND(A2>0,B2<100),TRUE, FALSE) 如果 A2 (25) 大于 0,并且 B2 (75) 小于 100,则返回 TRUE,否则返回 FALSE。 在本例中,两个条件都为 TRUE,因此返回 TRUE。
=IF(AND(A3=”Red”,B3=”Green”),TRUE,FALSE) 如果 A3(“蓝色”)=“红色”,并且 B3(“绿色”)等于“绿色”,则返回 TRUE,否则返回 FALSE。 在本例中,只有第一个条件为 TRUE,因此返回 FALSE。
=IF(OR(A5=”Red”,B5=”Green”),TRUE,FALSE) 如果 A5(“蓝色”)=“红色”,或者 B5(“绿色”)等于“绿色”,则返回 TRUE,否则返回 FALSE。 在本例中,第二个参数为 TRUE,因此公式返回 TRUE。
=IF(NOT(A6>50),TRUE,FALSE) 如果 A6 (25) 不大于 50,则返回 TRUE,否则返回 FALSE。 在本例中,25 不大于 50,因此公式返回 TRUE。
=IF(NOT(A7=”Red”),TRUE,FALSE) 如果 A7(“蓝色”)不等于“红色”,则返回 TRUE,否则返回 FALSE。

请注意,在所有示例中,输入各自的条件后都加了右括号。 其余 True/False 参数将作为外部 IF 语句的一部分。 你也可以将“文本”或“数字”值替换为示例中返回的 TRUE/FALSE 值。

文本函数

统计函数

SUMPRODUCT 函数-取单元格第一列之和

SUMPRODUCT函数返回相应范围或数组的个数之和。 默认操作是乘法,但也可以执行加减除运算。

本示例使用 SUMPRODUCT 返回给定项和大小的总销售额:

SUMPRODUCT 匹配项 Y/大小 M 的所有实例并求和,因此对于此示例,21 加 41 等于 62。

语法

若要使用默认操作 (乘法) :

=SUMPRODUCT (array1, [array2], [array3], …)

SUMPRODUCT 函数语法具有下列参数:

参数 说明
array1 必需 其相应元素需要进行相乘并求和的第一个数组参数。
[array2], [array3],… 可选 2 到 255 个数组参数,其相应元素需要进行相乘并求和。

执行其他算术运算

像往常一样使用 SUMPRODUCT,但请将分隔数组参数的逗号替换为所需的算术运算符 (*、/、+、-) 。 执行所有操作后,结果将像往常一样进行求和。

注意: 如果使用算术运算符,请考虑将数组参数括在括号中,并使用括号对数组参数进行分组以控制算术运算的顺序。

备注

数组参数必须具有相同的维数。 否则,函数 SUMPRODUCT 将返回 #VALUE! 错误值 #REF!。 例如,=SUMPRODUCT (C2:C10,D2:D5) 将返回错误,因为范围的大小不同。

SUMPRODUCT 将非数值数组条目视为零。

为获得最佳性能,SUMPRODUCT 不应与完整列引用一同使用。 请考虑 =SUMPRODUCT (A:A,B:B) ,在此函数将 A 列中的 1,048,576 个单元格乘以 B 列中的 1,048,576 个单元格,然后再添加它们。

示例 1

若要使用上面的示例列表创建公式,请键入 =SUMPRODUCT (C2:C5,D2:D5) 并按 Enter。 列 C 中的每个单元格乘以 D 列中同一行中的对应单元格,结果将相加。 杂货的总量为 $78.97。

若要编写提供相同结果的较长公式,请键入 =C2D2+C3D3+C4D4+C5D5,然后按 Enter。 按 Enter 后,结果相同:$78.97。 单元格 C2 乘以 D2,其结果将添加到单元格 C3 乘以单元格 D3 的结果,以此类比。

数学和三角函数

查找引用函数

财务函数

图表

根据散点找公式

技巧

录入相同内容

按住Ctrl键选中要填充内容的单元格,输入对应的内容后,按下Ctrl+回车组合键,批量完毕相同内容填充。

快速合并多行数据

先把列宽调整到可以放下合并的所有内容大小,接着选中数据,点击开始-编辑-填充-两端对齐,就能快速合并。

文本分多行

一个单元格有很多内容,如果分布多个单元格中?将单元格宽度调整到要分列的字符大小宽度,然后点击开始-编辑-填充-两端对齐,就能将内容分布多行。

单元格添加下拉选

excel单元格怎么添加百分比进度条

  1. 打开Excel表格,选择要设置进度条的单元格,展开条件格式
  2. 展开数据条,选择进度条颜色,就可以实现百分比进度条展示了

检查单元格的一部分是否与特定文本匹配

若要执行此任务,请使用IF、SEARCHISNUMBER函数。

注意: SEARCH函数不区分大小写。

参考资料

excel技巧-全

excel教程

linxu日常运维常用命令

Linux 运维

常识

语法

Linux命令格式: command [-options] [parameter1] … 命令 选项 参数 说明: command: 命令名,相应功能的英文单词或单词的缩写 [-options]:选项,可用来对命令进行控制,也可以省略,[]代表可选 parameter1 …:传给命令的参数:可以是零个一个或多个.

文件

软链接与硬链接

软连接是指向另外一个文件的文件,类似Windows中的快捷方式文件。例如:ln -s /usr/share/zoneinfo/Asia/Shanghai2 mysoftlink

  1. 被连接的文件名(路径)建议采用绝对路径
  2. 错误的软连接(又名断开)使用 ls -l 的时候显示的是红色
  3. 软连接是一个文件,其在硬盘中是存在数据块的
  4. 软连接文件的数据库中存储的是路径信息,而非真正的数据
  5. 软连接可能是多级嵌套的,例如:B连接A,C连接B,D连接C

硬连接相对于软连接来说,理解会困难一点点。硬连接是把不同的文件名对应到同一个存储块节点上。例如:ln /data/mymedia.mp4 mymedia2.mp4

  1. 被连接的文件名(路径)建议采用绝对路径
  2. 如果一个文件增加了对应的硬连接,那么删除文件的时候不会删除数据
  3. 硬连接文件存储的是真实数据块位置
  4. 只能对文件建立硬连接,而不能对一个目录建立硬连接

文件树

绝对路径与相对路径

  • 绝对路径:从/目录开始描述的路径为绝对路径,如:/home
  • 相对路径:从当前位置开始描述的路径为相对路径,如:../../ 。.和.. :
  • 每个目录下都有.和..(可用ls -a查看);. 表示当前目录;.. 表示上一级目录,即父目录;根目录下的.和..都表示当前目录。

访问权限

用户能够控制一个给定的文件或目录的访问程度,一个文件或目录可能有读、写及执行权限:

  • 读权限(r) 对文件而言,具有读取文件内容的权限;对目录来说,具有浏览目录的权限。

  • 写权限(w) 对文件而言,具有新增、修改文件内容的权限;对目录来说,具有删除、移动目录内文件的权限。

  • 可执行权限(x) 对文件而言,具有执行文件的权限;对目录了来说该用户具有进入目录的权限。

    注意:通常,Unix/Linux系统只允许文件的属主(所有者)或超级用户改变文件的读写权限

常用命令

浏览文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
dxshelley@dxshelley:~$ cat /etc/nginx/nginx.conf
# less
#空格键:前进一页(一个屏幕);
#b 键:后退一页;
#回车键:前进一行;
#y 键:后退一行;
#上下键:回退或前进一行;
#d 键:前进半页;
#u 键:后退半页;
#q 键:停止读取文件,中止 less 命令;
#= 键:显示当前页面的内容是文件中的第几行到第几行以及一些其它关于本页内容的详细信息;
#h 键:显示帮助文档;
#/ 键:进入搜索模式后,按 n 键跳到一个符合项目,按 N 键跳到上一个符合项目,同时也可以输入正则表达式匹配
dxshelley@dxshelley:~$ less /etc/nginx/nginx.conf

dxshelley@dxshelley:~$ tail -f /var/log/apache2/access.log

高频命令

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# 递归创建目录
dxshelley@dxshelley:~$ mkdir -p one/two/three
# 复制目录
dxshelley@dxshelley:~$ cp -r log one/two/three/
## 环境变量
# 列出所有变量
set
# 列出所有环境变量
env
# 列出和设置环境变量
export
export varname=value
# 列出所有别名
alias

## 修改文件所有者
dxshelley@dxshelley:~$ sudo chown -R dxshelley:dxshelley one/two/
# 读写执行权限
find /data/wwwroot/ -type d -exec chmod 750 {} \;
find /data/wwwroot/ -type f -exec chmod 640 {} \;
## 修改文件权限
dxshelley@dxshelley:~$ chmod -R 777 one/two/three/
dxshelley@dxshelley:~$ chmod -R o-w one/two/three/

## 文件查找
find <何处> <何物> <做什么>
### 根据文件名查找
dxshelley@dxshelley:~$ find ./ -name '*.log'
### 根据文件大小查找
dxshelley@dxshelley:~$ find ./ -size +10M

## 压缩
dxshelley@dxshelley:~$ tar -zcvf test.tar.gz one/
## 解压到指定目录
dxshelley@dxshelley:~$ tar -zxvf test.tar.gz -C two

## 网络
# 显示 tcp,udp 的端口和进程等相关情况。
netstat -tunlp
netstat -tunlp | grep 端口号
# 查看服务器 22 端口的占用情况
lsof -i:22
# kill 端口对应的进程
kill -9 PID
# 查询当前服务器的连接数
ps aux | grep httpd | wc -l


## 磁盘/内存
# 查看磁盘空间
df -lh
# 查看内存使用
free -lh
# 查看当前目录下各文件、文件夹的大小
du -h –max-depth=1 *
# 查询当前目录总大小
du -sh
# 显示直接子目录文件及文件夹大小统计值
du -h –max-depth=0 *


## 查看哪些用户登录
dxshelley@dxshelley:~$ w
22:07:19 up 2 days, 5:42, 1 user, load average: 0.07, 0.08, 0.07
USER TTY 来自 LOGIN@ IDLE JCPU PCPU WHAT
dxshelle pts/0 192.168.5.1 21:44 0.00s 1.14s 0.00s w
dxshelley@dxshelley:~$


## 主机间文件复制
scp source_file destination_file
rsync -arv Images/ backups/ # 将Images 目录下的所有文件备份到 backups 目录下
rsync -arv Images/ root@192.x.x.x:backups/ # 同步到服务器的backups目录下

基本命令

查看历史命令-history

基本原理

Linux 命令的历史记录,会持久化存储,默认位置是当前用户家目录的 .bash_history 文件。

当 Linux 系统启动一个 Shell 时,Shell 会从 .bash_history 文件中,读取历史记录,存储在相应内存的缓冲区中。

当我们退出 Shell,比如按下 Ctrl+D 时,Shell 进程会把历史记录缓冲区的内容,写回到 .bash_history 文件中去

我们平时所操作的 Linux 命令,都会记录在_缓冲区_中。包括 history 命令所执行的历史命令管理,都是在操作_缓冲区_,而不是直接操作 .bash_history 文件。

基本用法

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# 最近操作命令列表
[demo@localhost ~]$ history
10 cat application.properties
11 cat ../hqcec_demo/application.properties
12 tail -500f logs/9001.log
13 tail -f logs/9001.log
14 cp -R files/* ../hqcec_demo/files/
15 ps -ef|grep 9001
# 显示最近N条历史命令
[demo@localhost ~]$ history 10
1001 history
1002 ll
1003 history
1004 ll
1005 vi application.properties
1006 history | grep vi
1007 history | grep hhhh
1008 history | grep wwww
1009 history
1010 history 10
[demo@localhost ~]$
# 重复指定第N条历史命令
[demo@localhost ~]$ !1007
history | grep hhhh
1007 history | grep hhhh
1011 history | grep hhhh
# 重复执行上一条命令
[demo@localhost ~]$ !!
history | grep hhhh
1007 history | grep hhhh
1011 history | grep hhhh
[demo@localhost ~]$
# 交互式搜索历史命令
# 在命令行输入 Ctrl+R 后,进入交互界面,键入需要搜索的关键字,如果匹配到多条命令,可以多次键入 Ctrl+R 来切换上一条匹配的命令。符合后,按下回车就可以执行该命令。
[demo@localhost ~]$
(reverse-i-search)`vi': vi start.sh
# 从历史命令中获取参数。例如:^代表首参数,$代表尾参数
[test@localhost ~]$ history 10
51 history
52 ll -h
53 ll
54 rm 9002.log
55 touch 9002.log
56 ll
57 ps -ef | grep java
58 touch java
59 ll
60 history 10
[test@localhost ~]$ ll
总用量 0
-rw-rw-r-- 1 test test 0 10月 22 21:17 9002.log
-rw-rw-r-- 1 test test 0 10月 22 21:18 java
[test@localhost ~]$ rm !55:$
rm 9002.log
[test@localhost ~]$ ll
总用量 0
-rw-rw-r-- 1 test test 0 10月 22 21:18 java
[test@localhost ~]$ touch !60:$
touch 10
[test@localhost ~]$ ll
总用量 0
-rw-rw-r-- 1 test test 0 10月 22 21:21 10
-rw-rw-r-- 1 test test 0 10月 22 21:18 java
[test@localhost ~]$ touch !58:^
touch java
[test@localhost ~]$
[test@localhost ~]$ touch a b c
[test@localhost ~]$ ll
总用量 0
-rw-rw-r-- 1 test test 0 10月 22 21:21 10
-rw-rw-r-- 1 test test 0 10月 22 21:25 a
-rw-rw-r-- 1 test test 0 10月 22 21:25 b
-rw-rw-r-- 1 test test 0 10月 22 21:25 c
-rw-rw-r-- 1 test test 0 10月 22 21:22 java
[test@localhost ~]$ history 5
73 ll
74 rm a c
75 touch a b c
76 ll
77 history 5
[test@localhost ~]$ rm !75:2
rm b
[test@localhost ~]$ ll
总用量 0
-rw-rw-r-- 1 test test 0 10月 22 21:21 10
-rw-rw-r-- 1 test test 0 10月 22 21:25 a
-rw-rw-r-- 1 test test 0 10月 22 21:25 c
-rw-rw-r-- 1 test test 0 10月 22 21:22 java
[test@localhost ~]$
# 历史命令列表显示时间戳
[demo@localhost ~]$ export HISTTIMEFORMAT='%F %T'
[demo@localhost ~]$ history 5
1018 2021-10-22 21:00:57history 10
1019 2021-10-22 21:03:45 ps -ef | grep java
1020 2021-10-22 21:03:50history 10
1021 2021-10-22 21:09:20export HISTTIMEFORMAT='%F %T'
1022 2021-10-22 21:09:26history 5
[demo@localhost ~]$
# 禁用历史记录
echo "export HISTSIZE=0" >> ~/.bash_profile
echo "export HISTFILESIZE=0" >> ~/.bash_profile
source ~/.bash_profile


#合适使用几个相关的环境变量,让你的 Linux 系统更安全:
#HISTSIZE:控制缓冲区历史记录的最大个数
#HISTFILESIZE:控制历史记录文件中的最大个数
#HISTIGNORE:设置哪些命令不记录到历史记录
#HISTTIMEFORMAT:设置历史命令显示的时间格式
#HISTCONTROL:扩展的控制选项

#如果在生产环境,这些环境变量需要持久化到配置文件 ~/.bash_profile
export HISTCONTROL=ignoreboth
# ignorespace: 忽略空格开头的命令
# ignoredups: 忽略连续重复命令
# ignoreboth: 表示上述两个参数都设置
# 设置追加而不是覆盖
shopt -s histappend
export HISTSIZE=1000
export HISTFILESIZE=200000
export HISTTIMEFORMAT="%F %T "
export HISTIGNORE="ls:history"

查看系统,CPU信息

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
# 查看系统版本
[root@localhost download]# cat /etc/system-release
CentOS Linux release 7.9.2009 (Core)

# Linux Version
lsb_release -a

# 查看系统内核信息
uname -a

# 查看系统内核版本
cat /proc/version

# 查看当前用户环境变量
env

cat /proc/cpuinfo

# 查看有几个逻辑cpu, 包括cpu型号
cat /proc/cpuinfo | grep name | cut -f2 -d: | uniq -c

# 查看有几颗cpu,每颗分别是几核
cat /proc/cpuinfo | grep physical | uniq -c

# 查看当前CPU运行在32bit还是64bit模式下, 如果是运行在32bit下也不代表CPU不支持64bit
getconf LONG_BIT

# 结果大于0, 说明支持64bit计算. lm指long mode, 支持lm则是64bit
cat /proc/cpuinfo | grep flags | grep ' lm ' | wc -l

进程相关

后台运行命令-nohup(not hang up)与 &

nohup命令的全称为“no hang up”,该命令可以将程序以忽略挂起信号的方式运行起来,被运行的程序的输出信息将不会显示到终端。注意了nohup没有后台运行的意思。

& : 指在后台运行

1
2
3
4
5
6
7
8
# 后台运行,并且有nohup.out输出 使命令永久的在后台执行。将xxx任务放到后台,但是依然可以使用标准输入,终端能够接收任何输入,重定向标准输出和标准错误到当前目录下的nohup.out文件,即使关闭xshell退出当前session依然继续运行
nohup xxx &

# 后台运行, 不输出任何日志
nohup xxx > /dev/null &

# 后台运行, 并将错误信息做标准输出到日志中
nohup xxx >out.log 2>&1 &
1
2
3
4
$ nohup python /data/python/server.py > python.log 2>&1 &
$ nohup python -u test.py > out.log 2>&1 &
# 只输出错误信息到日志文件
$ nohup ./program >/dev/null 2>log &

说明:

  1. 1是标准输出(STDOUT)的文件描述符,2是标准错误(STDERR)的文件描述符,1> python.log 简化为 > python.log,表示把标准输出重定向到python.log这个文件

  2. 2>&1 表示把标准错误重定向到标准输出,这里&1表示标准输出。为什么需要将标准错误重定向到标准输出的原因,是因为标准错误没有缓冲区,而STDOUT有。这就会导致 commond > python.log 2 > python.log 文件python.log被两次打开,而STDOUT和 STDERR将会竞争覆盖,这肯定不是我门想要的

  3. python的输出有缓冲,导致python.log并不能够马上看到输出。使用-u参数,使得python不启用缓冲

任务前后台切换

shell支持作用控制,有以下命令实现前后台切换:

  1. command &让进程在后台运行
  2. jobs 查看后台运行的进程
  3. fg %n 让后台运行的进程n到前台来
  4. bg %n 让进程n到后台去
  5. kill %n 杀死job
  6. ctrl + z 将一个正在前台执行的命令放到后台,并且暂停
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
dxshelley@dxshelley:~$ 
dxshelley@dxshelley:~$ jobs
[1]+ 运行中 python3 -m http.server 9092 &
dxshelley@dxshelley:~$ fg %1
python3 -m http.server 9092
^Z
[1]+ 已停止 python3 -m http.server 9092
dxshelley@dxshelley:~$ bg %1
[1]+ python3 -m http.server 9092 &

dxshelley@dxshelley:~$ kill %1
dxshelley@dxshelley:~$ jobs
[1]+ 已终止 python3 -m http.server 9092
dxshelley@dxshelley:~$ fg %1
-bash: fg: 1:无此任务
dxshelley@dxshelley:~$

进程查看

1
2
3
4
5
6
7
8
9
#查看进程所有打开最大fd数
ulimit -n
#查看命令路径
which <命令>
#查看进程内加载的环境变量
# 也可以去 cd /proc 目录下, 查看进程内存中加载的东西
ps -ef | grep java
ps eww -p XXXXX(进程号)
ps aux|grep xxx | grep -v grep | awk '{print $2}' | xargs kill -9

输入输出重定向

简而言之,输入重定向是指把文件导入到命令中,而输出重定向则是指把原本要输出到屏幕的数据信息写入到指定文件中。

标准输入重定向(STDIN,文件描述符为0):默认从键盘输入,也可从其他文件或命令中输入。

标准输出重定向(STDOUT,文件描述符为1):默认输出到屏幕。

错误输出重定向(STDERR,文件描述符为2):默认输出到屏幕。

对于输入重定向来讲,用到的符号及其作用如表3-1所示。

表3-1 输入重定向中用到的符号及其作用

符号 作用
命令 < 文件 将文件作为命令的标准输入
命令 << 分界符 从标准输入中读入,直到遇见分界符才停止
命令 < 文件1 > 文件2 将文件1作为命令的标准输入并将标准输出到文件2

对于输出重定向来讲,用到的符号及其作用如表3-2所示。

表3-2 输出重定向中用到的符号及其作用

符号 作用
命令 > 文件 或 命令 1> 文件 将标准输出重定向到一个文件中(清空原有文件的数据)
命令 2> 文件 将错误输出重定向到一个文件中(清空原有文件的数据)
命令 >> 文件 或 命令 1>> 文件 将标准输出重定向到一个文件中(追加到原有内容的后面)
命令 2>> 文件 将错误输出重定向到一个文件中(追加到原有内容的后面)
命令 >> 文件 2>&1 或 命令 &>> 文件 将标准输出与错误输出共同写入到文件中(追加到原有内容的后

对于重定向中的标准输出模式,可以省略文件描述符1不写,而错误输出模式的文件描述符2是必须要写的。

管道命令符

把前一个命令原本要输出到屏幕的信息当作后一个命令的标准输入。

用户相关

1
2
3
4
5
6
7
8
9
# 新增用户
useradd 用户名
passwd 用户名

#增加sudo权限
vim /etc/sudoers
# 修改文件里面的
# root ALL=(ALL) ALL
# 用户名 ALL=(ALL) ALL

文件相关

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
[hqc@testserver hqcec_test]$ stat tomcat/
File: ‘tomcat/’
Size: 47 Blocks: 0 IO Block: 4096 directory
Device: fd02h/64770d Inode: 108478460 Links: 5
Access: (0775/drwxrwxr-x) Uid: ( 1001/ hqc) Gid: ( 1001/ hqc)
Context: unconfined_u:object_r:user_home_t:s0
Access: 2022-01-10 18:51:26.596807729 +0800
Modify: 2021-10-08 11:52:16.183331973 +0800
Change: 2021-10-08 11:52:16.220331972 +0800
Birth: -
[hqc@testserver hqcec_test]$ stat --help
Usage: stat [OPTION]... FILE...
Display file or file system status.

Mandatory arguments to long options are mandatory for short options too.
-L, --dereference follow links
-f, --file-system display file system status instead of file status
-c --format=FORMAT use the specified FORMAT instead of the default;
output a newline after each use of FORMAT
--printf=FORMAT like --format, but interpret backslash escapes,
and do not output a mandatory trailing newline;
if you want a newline, include \n in FORMAT
-t, --terse print the information in terse form
--help display this help and exit
--version output version information and exit

网络相关

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
#查看什么进程使用了该端口
lsof -i:port


#获取本机IP地址
/sbin/ifconfig -a|grep inet|grep -v 127.0.0.1|grep -v inet6|awk '{print $2}'|tr -d "addr:"


# nc命令, tcp调试利器
#给某一个endpoint发送TCP请求,就将data的内容发送到对端
nc 192.168.0.11 8000 < data.txt

#nc可以当做服务器,监听某个端口号,把某一次请求的内容存储到received_data里
nc -l 8000 > received_data
#上边只监听一次,如果多次可以加上-k参数
nc -lk 8000

# dump出本机12301端口的tcp包
tcpdump -i em1 tcp port 12301 -s 1500 -w abc.pcap

#netstat
# 输出每个ip的连接数,以及总的各个状态的连接数
netstat -n | awk '/^tcp/ {n=split($(NF-1),array,":");if(n<=2)++S[array[(1)]];else++S[array[(4)]];++s[$NF];++N} END {for(a in S){printf("%-20s %s\n", a, S[a]);++I}printf("%-20s %s\n","TOTAL_IP",I);for(a in s) printf("%-20s %s\n",a, s[a]);printf("%-20s %s\n","TOTAL_LINK",N);}'

# 统计所有连接状态,
# CLOSED:无连接是活动的或正在进行
# LISTEN:服务器在等待进入呼叫
# SYN_RECV:一个连接请求已经到达,等待确认
# SYN_SENT:应用已经开始,打开一个连接
# ESTABLISHED:正常数据传输状态
# FIN_WAIT1:应用说它已经完成
# FIN_WAIT2:另一边已同意释放
# ITMED_WAIT:等待所有分组死掉
# CLOSING:两边同时尝试关闭
# TIME_WAIT:主动关闭连接一端还没有等到另一端反馈期间的状态
# LAST_ACK:等待所有分组死掉
netstat -n | awk '/^tcp/ {++state[$NF]} END {for(key in state) print key,"\t",state[key]}'

# 查找较多time_wait连接
netstat -n|grep TIME_WAIT|awk '{print $5}'|sort|uniq -c|sort -rn|head -n20

linux系统查看网卡是否支持WOL网络唤醒并开启WOL唤醒功能

首先需要看电脑的主板是否支持,进入BIOS,一般有两种。

一是在开机启动项里是否有Lan启动的选项,有的话就调成优先启动

二是在电源里,有的直接有WOL选项,开启即可。

硬件开启了网络唤醒功能,接下来就需要在系统里设置了。

检查是否开启WOL唤醒功能

linux检查网卡是否支持唤醒功能,输入命令命令打印出网卡的信息。

1
ethtool eth0

其中eth0是一般服务器,默认的网卡,但是也有例外,所以先用命令 ifconfig 查看下所有网络设备,找到你的电脑的网卡,像我的就是eno1。

其中先看Supports Wake-on的字段,会输出现在网卡支持哪些功能,若为d,则不支持。

  • d – 禁用
  • p – 物理活动唤醒
  • u – 单播消息唤醒
  • m – 多播(组播)消息唤醒
  • b – 广播消息唤醒
  • a – ARP 唤醒
  • g – 特定数据包magic packet唤醒
  • s – 设有密码的特定数据包magic packet唤醒

然后看Wake-on的值,若为g,表示网卡已开启远程唤醒功能;

开启WOL唤醒功能

若为d,则需要输入命令开启。记得将网卡改成自己电脑的。

1
ethtool -s eth0 wol g

命令执行后,再次输入ethtool eth0,检测是否成功开启wake on lan功能。

为什么这里选择的g,因为其他只是单纯的唤醒,并没有验证,可能路由器的一个广播操作都会将电脑给唤醒,g为特定数据包magic packet唤醒,唤醒的时候是发送一段特殊的代码,进行操作。

幻数据包(Magic Packet) 由 AMD 公司提出,幻数据包是一个广播帧,包含待唤醒计算机的MAC地址。完成的幻数据包最简单的构成是6字节的255(FF FF FF FF FF FF FF),紧接着为48位MAC地址,重复16次,数据包共计102字节。通常数据包含在 UDP协议中。

重启后自动开启WOL唤醒

每次重启完,网卡的Wake-on属性又会恢复到d的关闭状态,所以每次开机需要再开启,两种方法:

1、加入开机启动项。将以下代码添加至/etc/rc.local

1
/sbin/ethtool -s eth0 wol g

2、修改网卡属性。编辑/etc/sysconfig/network-scripts/ifcfg-eth0,添加以下代码

1
ETHTOOL_OPTS=”wol g”

PS:要注意将eth0换成自己的网卡

系统日志

1
dmesg

文本搜索-grep

Linux系统中grep命令是一种强大的文本搜索工具,grep允许对文本文件进行模式查找。如果找到匹配模式, grep打印包含模式的所有行。 grep一般格式为:grep [-选项] ‘搜索内容串’文件名 在grep命令中输入字符串参数时,最好引号或双引号括起来。例如:grep‘a ’1.txt。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 反向匹配, 查找不包含xxx的内容
grep -v xxx

# 排除所有空行
grep -v '^/pre>

# 返回结果 2,则说明第二行是空行
grep -n “^$” 111.txt

# 查询以abc开头的行
grep -n “^abc” 111.txt

# 同时列出该词语出现在文章的第几行
grep 'xxx' -n xxx.log

# 计算一下该字串出现的次数
grep 'xxx' -c xxx.log

# 比对的时候,不计较大小写的不同
grep 'xxx' -i xxx.log

查找文件-find

find支持文件名的正则表达式查找,按文件修改时间查找,按文件大小查找,按文件权限查找,按文件类型查找等,查找到以后还支持直接对查找到的文件使用命令,功能非常强大。

典型的find命令的写法是:find 查找路径 查找的标准 查找到之后的动作。 比如: find /home -type d -ls,意思是: 找出/home/下所有的目录,并显示目录的详细信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 在目录下找后缀是.mysql的文件
find /home/eagleye -name '*.mysql' -print

# 会从 /usr 目录开始往下找,找最近3天之内存取过的文件。
find /usr -atime 3 –print

# 会从 /usr 目录开始往下找,找最近5天之内修改过的文件。
find /usr -ctime 5 –print

# 会从 /doc 目录开始往下找,找jacky 的、文件名开头是 j的文件。
find /doc -user jacky -name 'j*'print

# 会从 /doc 目录开始往下找,找寻文件名是 ja 开头或者 ma开头的文件。
find /doc \( -name 'ja*' -o- -name 'ma*' \) –print

# 会从 /doc 目录开始往下找,找到凡是文件名结尾为 bak的文件,把它删除掉。-exec 选项是执行的意思,rm 是删除命令,{ } 表示文件名,“\;”是规定的命令结尾。
find /doc -name '*bak' -exec rm {} \;

归档管理-tar

1
2
3
4
5
6
7
8
9
10
11
12
#文件打包
tar -cvf ***.tar 1.py 2.py 3.txt *.c
#文件解包
tar -xvf ***.tar -C ~/Desktop
#压缩用法
tar -zcvf 压缩包包名 文件1 文件2 ... -z :指定压缩包的格式为:file.tar.gz
#解压用法
tar -zxvf 压缩包包名 解压到指定目录:-C (大写字母“C”)
#压缩用法
tar jcvf 压缩包包名 文件...(tar jcvf bk.tar.bz2 *.c)
#解压用法
tar jxvf 压缩包包名 (tar jxvf bk.tar.bz2)

文件压缩-zip/unzip

1
2
3
4
#压缩文件
zip [-r] 目标文件(没有扩展名) 源文件
#解压文件
unzip -d 解压后目录文件 压缩文件

修改文件权限-chmod

chmod 修改文件权限有两种使用格式:字母法与数字法。 字母法:chmod u/g/o/a +/-/= rwx 文件

注意要递归修改权限的话,需要加上-R

当前日历-cal

cal(calendar)命令用于查看当前日历,-y显示整年日历

磁盘空间查看-df

df(disk free)命令用于检测文件系统的磁盘空间占用和空余情况,可以显示所有文件系统对节点和磁盘块的使用情况。

1
2
3
4
5
6
7
8
9
10
11
[hqc@localhost hqctest]$ df -h
Filesystem Size Used Avail Use% Mounted on
devtmpfs 7.8G 0 7.8G 0% /dev
tmpfs 7.8G 0 7.8G 0% /dev/shm
tmpfs 7.8G 820M 7.0G 11% /run
tmpfs 7.8G 0 7.8G 0% /sys/fs/cgroup
/dev/mapper/centos-root 50G 4.8G 46G 10% /
/dev/vda1 1014M 220M 795M 22% /boot
/dev/mapper/centos-home 142G 7.2G 134G 6% /home
tmpfs 1.6G 16K 1.6G 1% /run/user/42
tmpfs 1.6G 0 1.6G 0% /run/user/1001

目录所占磁盘空间-du

du(disk usage)命令用于统计目录或文件所占磁盘空间的大小,该命令的执行结果与df类似,du更侧重于磁盘的使用状况。 du命令的使用格式如下: `du [选项] 目录或文件名

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
[hqc@localhost hqctest]$ du -h -c -d 1
89M ./logs
217M ./spire-html2pdf-plugins
2.1G ./files
135M ./tomcat
157M ./gikamlib
240M ./thirdlib
191M ./finelib
3.3G .
3.3G total
[hqc@localhost hqctest]$ du -h -c -d 2
89M ./logs
22M ./spire-html2pdf-plugins/translations
18M ./spire-html2pdf-plugins/resources
2.6M ./spire-html2pdf-plugins/plugins
16K ./spire-html2pdf-plugins/libexec
174M ./spire-html2pdf-plugins/lib
692K ./spire-html2pdf-plugins/doc
217M ./spire-html2pdf-plugins
6.4M ./files/temp
2.1G ./files/secure
188K ./files/finereport
2.1G ./files
18M ./tomcat/WEB-INF
117M ./tomcat/logs
160K ./tomcat/backup
135M ./tomcat
157M ./gikamlib
240M ./thirdlib
191M ./finelib
3.3G .
3.3G total

# 查看当前目录下各个文件, 文件夹占了多少空间, 不会递归
[hqc@localhost hqctest]$ du -sh *
4.0K application.properties
36K EcApiMidMrServiceImpl.java
2.1G files
191M finelib
13M gikam-escm-hqcec-0.10.0.jar
15M gikam-escm-hqcec-1.1.0.jar
14M gikam-escm-hqcec-1.1.0.jar.20210922
14M gikam-escm-hqcec-1.1.0.jar.20211014
15M gikam-escm-hqcec-1.1.0.jar.2021101501
157M gikamlib
95M logs
18M simsun.ttc
217M spire-html2pdf-plugins
4.0K start.sh
120K sunway-app.so
240M thirdlib
139M tomcat
18M tools.jar
38M wkhtmltopdf
[hqc@localhost hqctest]$ du -sh
3.3G .
[hqc@localhost hqctest]$

内存查看-free

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
free -m

eg:

total used free shared buffers cached
Mem: 1002 769 232 0 62 421
-/+ buffers/cache: 286 715
Swap: 1153 0 1153

第一部分Mem行:
total 内存总数: 1002M
used 已经使用的内存数: 769M
free 空闲的内存数: 232M
shared 当前已经废弃不用,总是0
buffers Buffer 缓存内存数: 62M
cached Page 缓存内存数:421M

关系:total(1002M) = used(769M) + free(232M)

第二部分(-/+ buffers/cache):
(-buffers/cache) used内存数:286M (指的第一部分Mem行中的used – buffers – cached)
(+buffers/cache) free内存数: 715M (指的第一部分Mem行中的free + buffers + cached)

可见-buffers/cache反映的是被程序实实在在吃掉的内存,而+buffers/cache反映的是可以挪用的内存总数.

第三部分是指交换分区

vi技巧

基础

光标移动

行内移动
命令 英文 功能
w word 向后移动一个单词
b back 向前移动一个单词
0 行首
^ 行首,第一个不是空白字符的位置
$ 行尾
行数移动
命令 英文 功能
gg go 文件顶部
G go 文件末尾
数字gg go 移动到 数字 对应行数
数字G go 移动到 数字 对应行数
:数字 移动到 数字 对应行数
屏幕移动
命令 英文 功能
Ctrl + b back 向上翻页
Ctrl + f forward 向下翻页
H Head 屏幕顶部
M Middle 屏幕中间
L Low 屏幕底部
段落移动
  • vi 中使用 空行 来区分段落
  • 在程序开发时,通常 一段功能相关的代码会写在一起 —— 之间没有空行
命令 功能
{ 上一段
} 下一段
括号匹配
  • 在程序世界中,()[]{} 使用频率很高,而且 都是成对出现的
命令 功能
% 括号匹配及切换

文本编辑

插入命令
  • vi 中除了常用的 i 进入 编辑模式 外,还提供了以下命令同样可以进入编辑模式:
命令 英文 功能 常用
i insert 在当前字符前插入文本 常用
I insert 在行首插入文本 较常用
a append 在当前字符后添加文本
A append 在行末添加文本 较常用
o 在当前行后面插入一空行 常用
O 在当前行前面插入一空行 常用
撤销和恢复撤销
  • 在学习编辑命令之前,先要知道怎样撤销之前一次 错误的 编辑动作!
命令 英文 功能
u undo 撤销上次命令
CTRL + r redo 恢复撤销的命令
缩排和重复执行
命令 功能
>> 向右增加缩进
<< 向左减少缩进
. 重复上次命令
替换
命令 英文 功能 工作模式
r replace 替换当前字符 命令模式
R replace 替换当前行光标后的字符 替换模式
  • R 命令可以进入 替换模式,替换完成后,按下 ESC 可以回到 命令模式
  • 替换命令 的作用就是不用进入 编辑模式,对文件进行 轻量级的修改

查找替换

常规查找
命令 功能
/str 查找 str
?str 反向查找str
  • 查找下一个出现的位置:
    • n: 查找下一个
    • N: 查找上一个
  • 如果不想看到高亮显示,可以随便查找一个文件中不存在的内容即可
单词快速匹配
命令 功能
* 向后查找当前光标所在单词
# 向前查找当前光标所在单词

在开发中,通过单词快速匹配,可以快速看到这个单词在其他什么位置使用过

查找并替换
  • vi 中查找和替换命令需要在 末行模式 下执行
  • 记忆命令格式:
1
:%s///g
1) 全局替换
  • 一次性替换文件中的 所有出现的旧文本
  • 命令格式如下:
1
:%s/旧文本/新文本/g
2) 可视区域替换
  • 先选中 要替换文字的 范围
  • 命令格式如下:
1
:s/旧文本/新文本/g
3) 确认替换
  • 如果把末尾的 g 改成 gc 在替换的时候,会有提示!推荐使用!

c表示conform。

1
:%s/旧文本/新文本/gc
  1. y - yes 替换
  2. n - no 不替换
  3. a - all 替换所有
  4. q - quit 退出替换
  5. l - last 最后一个,并把光标移动到行首
  6. ^E 向下滚屏
  7. ^Y 向上滚屏

场景

演练 1 —— 编辑命令和数字连用
  • 在开发中,可能会遇到连续输入 N 个同样的字符

Python 中有简单的方法,但是其他语言中通常需要自己输入

  • 例如:********** 连续 10 个星号

要实现这个效果可以在 命令模式

  1. 输入 10,表示要重复 10 次
  2. 输入 i 进入 编辑模式
  3. 输入 * 也就是重复的文字
  4. 按下 ESC 返回到 命令模式,返回之后 vi 就会把第 2、3 两步的操作重复 10

提示:正常开发时,在 进入编辑模式之前,不要按数字

演练 2 —— 利用 可视块 给多行代码增加注释
  • 在开发中,可能会遇到一次性给多行代码 增加注释 的情况

Python 中,要给代码增加注释,可以在代码前增加一个 #

要实现这个效果可以在 命令模式

  1. 移动到要添加注释的 第 1 行代码,按 ^ 来到行首
  2. CTRL + v 进入 可视块 模式
  3. 使用 j 向下连续选中要添加的代码行
  4. 输入 I 进入 编辑模式,并在 行首插入,注意:一定要使用 I
  5. 输入 # 也就是注释符号
  6. 按下 ESC 返回到 命令模式,返回之后 vi 会在之前选中的每一行代码 插入 #

linux 日常运维

ssh登录

ssh [-p port] user@remote命令中有三个要素:

  • user是远程机器上的用户名,如果不指定的话默认为当前用户。
  • remote是远程机器的地址,可以是 IP域名 ,或者是后面会提到的 别名
  • portSSH Server监听的端口,如果不指定,就为默认值22

有关ssh配置的信息都放在用户家目录下.ssh目录下。

免密码登录

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
[root@testserver system]# ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:Y+9vfKv86U6FiCURQv80QFywIrW+FK4VXNj8PdQXjvw root@testserver
The key's randomart image is:
+---[RSA 2048]----+
| .+*B+. o.|
| o.=++. + o|
| . * +.+= ..|
| + + *.o+. |
| S . o .E.|
| = + . |
| . . .. . |
| . .o... |
| .o+**. |
+----[SHA256]-----+
[root@testserver system]#
[root@testserver system]#
[root@testserver system]#
[root@testserver system]# ssh-copy-id root@10.115.13.137
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
root@10.115.13.137's password:

Number of key(s) added: 1

Now try logging into the machine, with: "ssh 'root@10.115.13.137'"
and check to make sure that only the key(s) you wanted were added.

[root@testserver system]#

配置别名

每次都输入ssh -p port user@remote,时间久了会觉得很麻烦,特别是当user, remoteport都得输入,而且还不好记忆,而** 配置别名 **可以让我们进一步偷懒,譬如用:ssh mac来替代上面这么一长串,那么就在~/.ssh/config里面追加以下内容:

1
2
3
4
5
Host hqc-dev-root
HostName 10.115.13.137
User root
Port 22
~

远程拷贝文件-scp

scp就是 secure copy,是一个在Linux下来进行远程拷贝文件的命令。 它的地址格式与ssh基本相同,需要注意的是,在指定端口时用的是大写的-P.

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
# 复制本机单个文件到目标主机,目标主机需要指定已存在文件夹或指定文件名(类似重命名)
[hqc@localhost hqctest]$ scp application.properties test@172.16.29.61:/home/test/
[hqc@localhost hqctest]$ scp application.properties test@172.16.29.61:/home/test/application.properties2
# 复制本机多个文件到目标主机,目标主机需要指定已存在文件夹
[hqc@localhost hqctest]$ scp application.properties start.sh test@172.16.29.61:/home/test
# 复制本机指定文件夹下多个文件到目标主机,目标主机需要指定已存在文件夹
# 目标主机文件夹加不加最后的斜杠,两者效果一样
[hqc@localhost hqctest]$ scp logs/* test@172.16.29.61:/home/test
[hqc@localhost hqctest]$ scp logs/* test@172.16.29.61:/home/test/

# 估值本机指定文件夹到目标主机,目标主机需要指定已存在文件夹.本机主机文件夹加不加最后的斜杠,两者效果一样,在复制目录时,会将源路径的最后一级目录全部复制过去,包括它本身.
[hqc@localhost hqctest]$ scp -r gikamlib test@172.16.29.61:/home/test
[hqc@localhost hqctest]$ scp -r gikamlib/ test@172.16.29.61:/home/test
test@172.16.29.61's password:
gikam-core-fr-interface-1.1.0.jar 100% 11KB 6.2MB/s 00:00
gikam-core-common-1.1.6.jar 100% 66MB 86.9MB/s 00:00
[hqc@localhost hqctest]$

#在两台remote主机之间复制文件
scp 192.168.1.88:/root/something.tar.gz lisi@192.168.1.99:/home/lisi/
#通过本地主机中转,在两台remote主机之间复制文件夹
scp -3 -r zhangsan@192.168.1.88:/home/zhangsan/docs/ lisi@192.168.1.99:/home/lisi/docs/


# 复制目标主机到本机同理

安装软件包

yum

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# 语法
yum(选项)(参数)
选项
-h:显示帮助信息;
-y:对所有的提问都回答“yes”;
-c:指定配置文件;
-q:安静模式;
-v:详细模式;
-d:设置调试等级(0-10);
-e:设置错误等级(0-10);
-R:设置yum处理一个命令的最大等待时间;
-C:完全从缓存中运行,而不去下载或者更新任何头文件。
# 参数
install:安装rpm软件包;
update:更新rpm软件包;
check-update:检查是否有可用的更新rpm软件包;
remove:删除指定的rpm软件包;
list:显示软件包的信息;
search:检查软件包的信息;
info:显示指定的rpm软件包的描述信息和概要信息;
clean:清理yum过期的缓存;
shell:进入yum的shell提示符;
resolvedep:显示rpm软件包的依赖关系;
localinstall:安装本地的rpm软件包;
localupdate:显示本地rpm软件包进行更新;
deplist:显示rpm软件包的所有依赖关系。
# 实例
部分常用的命令包括:
自动搜索最快镜像插件:yum install yum-fastestmirror
安装yum图形窗口插件:yum install yumex
查看可能批量安装的列表:yum grouplist

# 安装
yum install #全部安装
yum install package1 #安装指定的安装包package1
yum groupinsall group1 #安装程序组group1

# 更新和升级
yum update #全部更新
yum update package1 #更新指定程序包package1
yum check-update #检查可更新的程序
yum upgrade package1 #升级指定程序包package1
yum groupupdate group1 #升级程序组group1

# 查找和显示
# 检查 MySQL 是否已安装
yum list installed | grep mysql
yum list installed mysql*

yum info package1 #显示安装包信息package1
yum list #显示所有已经安装和可以安装的程序包
yum list package1 #显示指定程序包安装情况package1
yum groupinfo group1 #显示程序组group1信息yum search string 根据关键字string查找安装包

# 删除程序
yum remove &#124; erase package1 #删除程序包package1
yum groupremove group1 #删除程序组group1
yum deplist package1 #查看程序package1依赖情况

# 清除缓存
yum clean packages #清除缓存目录下的软件包
yum clean headers #清除缓存目录下的 headers
yum clean oldheaders #清除缓存目录下旧的 headers

# 配置yum源
/etc/yum.repos.d/ yum 源配置文件
vi /etc/yum.repos.d/nginx.repo # 举个栗子: nginx yum源
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/6/$basearch/
gpgcheck=0
enabled=1

# yum mirror
mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak
wget https://mirror.tuna.tsinghua.edu.cn/help/centos/
yum makecache

# 添加中文语言支持
LANG=C # 原始语言
LANG=zh_CN.utf8 # 切换到中文
yum groupinstall "Chinese Support" # 添加中文语言支持

Yum自动下载RPM包及其所有依赖的包

1
yum install --downloadonly --downloaddir=/root/mypackages/  nginx

时间设置

概念

时区

整个地球分为二十四时区,每个时区都有自己的本地时间。在国际无线电通信场合,为了统一起见,使用一个统一的时间,称为通用协调时间(UTC, Universal Time Coordinated)。

格林威治标准时间 (GMT, Greenwich Mean Time)指位于英国伦敦郊区的皇家格林尼治天文台的标准时间,因为本初子午线被定义在通过那里的经线。

中国标准时间 (China Standard Time)

GMT + 8 = UTC + 8 = CST

系统时间与硬件时间

在Windwos中,系统时间的设置很简单,界面操作,通俗易懂。而且设置后,重启,关机都没关系。系统时间会自动保存在Bios的时钟里面,启动计算机的时候,系统会自动在Bios里面取硬件时间,以保证时间的不间断。

但在Linux下,默认情况下,系统时间和硬件时间,并不会自动同步。在Linux运行过程中,系统时间和硬件时间以异步的方式运行,互不干扰。硬件时间的运行,是靠Bios电池来维持,而系统时间,是用CPU tick来维持的。

在系统开机的时候,会自动从Bios中取得硬件时间,设置为系统时间

一台Linux服务器有两个时间源,一个是硬件时间,即服务器硬件CMOS维护的时间,还有一个是软件时间,即操作系统维护的时间,前者通过hwclock命令来访问,后者则主要通过date命令来访问。

修改linux服务器时区

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# 查看时间
[test@localhost ~]$ date -R
Thu, 21 Oct 2021 10:07:56 +0800
[test@localhost ~]$ date
2021年 10月 21日 星期四 10:08:02 CST

# 查看时区
[test@localhost ~]$ ll /etc/localtime
lrwxrwxrwx. 1 root root 35 3月 16 2020 /etc/localtime -> ../usr/share/zoneinfo/Asia/Shanghai
[test@localhost ~]$
##### 针对当前用户
# 使用tzselect指引,用于生产修改指引,命令本身并不会修改系统时间。
[test@localhost ~]$ tzselect
Please identify a location so that time zone rules can be set correctly.
Please select a continent or ocean.
1) Africa
2) Americas
3) Antarctica
4) Arctic Ocean
5) Asia
6) Atlantic Ocean
7) Australia
8) Europe
9) Indian Ocean
10) Pacific Ocean
11) none - I want to specify the time zone using the Posix TZ format.
#? 5
Please select a country.
1) Afghanistan 18) Israel 35) Palestine
2) Armenia 19) Japan 36) Philippines
3) Azerbaijan 20) Jordan 37) Qatar
4) Bahrain 21) Kazakhstan 38) Russia
5) Bangladesh 22) Korea (North) 39) Saudi Arabia
6) Bhutan 23) Korea (South) 40) Singapore
7) Brunei 24) Kuwait 41) Sri Lanka
8) Cambodia 25) Kyrgyzstan 42) Syria
9) China 26) Laos 43) Taiwan
10) Cyprus 27) Lebanon 44) Tajikistan
11) East Timor 28) Macau 45) Thailand
12) Georgia 29) Malaysia 46) Turkmenistan
13) Hong Kong 30) Mongolia 47) United Arab Emirates
14) India 31) Myanmar (Burma) 48) Uzbekistan
15) Indonesia 32) Nepal 49) Vietnam
16) Iran 33) Oman 50) Yemen
17) Iraq 34) Pakistan
#? 9
Please select one of the following time zone regions.
1) Beijing Time
2) Xinjiang Time
#? 1

The following information has been given:

China
Beijing Time

Therefore TZ='Asia/Shanghai' will be used.
Local time is now: Thu Oct 21 10:09:38 CST 2021.
Universal Time is now: Thu Oct 21 02:09:38 UTC 2021.
Is the above information OK?
1) Yes
2) No
#? 1

You can make this change permanent for yourself by appending the line
TZ='Asia/Shanghai'; export TZ
to the file '.profile' in your home directory; then log out and log in again.

Here is that TZ value again, this time on standard output so that you
can use the /usr/bin/tzselect command in shell scripts:
Asia/Shanghai
[test@localhost ~]$

##### 针对所有用户,永久生效
#如果想针对所有用户生效,修改/etc/localtime,/etc/localtime是一个链接文件,指向时区文件存放的位置/usr/share/zoneinfo/XXX/YYY
#强制/etc/localtime软链接到/usr/share/zoneinfo/Asia/Shanghai
[test@localhost ~]$ ll /etc/localtime
lrwxrwxrwx. 1 root root 35 3月 16 2020 /etc/localtime -> ../usr/share/zoneinfo/Asia/Shanghai
[test@localhost ~]$ ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
ln: 无法删除"/etc/localtime": 权限不够
[test@localhost ~]$

修改Linux时间

修改系统时间
1
2
3
4
5
6
7
# 需要注意的是设置时间需要root的权限。
# 将系统时间设定成2010年4月5日
[root@rhel ~]# date -s 20100405
# 将系统时间设定成14点31分0秒
[root@rhel ~]# date -s 14:31:00
# 以上日期和时间也可以一次输入完成:(此时日期和时间用双引号引起来)
[root@rhel ~]# date -s "20100405 14:31:00"
修改硬件时间

hwclock命令用于访问服务器的硬件CMOS时间,无论读取还是设置都需要root权限。

1
2
3
4
5
6
7
8
9
# 获取系统硬件时间
$ sudo hwclock
Fri 23 Jan 2015 03:33:17 PM CST -0.567492 seconds

# 设置操作系统的软件时间,与系统硬件时间同步
$ sudo hwclock -s

# 设置系统硬件时间,与操作系统的软件时间同步
$ sudo hwclock -w

从CentOS 7开始,使用了一个新的时间工具timedatectl

1
2
3
4
5
6
7
8
#使用timedatectl读取时间
[root@zcwyou ~]# timedatectl
[root@zcwyou ~]# timedatectl list-timezones

#使用timedatectl设置时间
[root@zcwyou ~]# timedatectl set-time "2018-11-24 12:00:30"
[root@zcwyou ~]# timedatectl set-timezone Asia/Shanghai
[root@zcwyou ~]# timedatectl set-ntp yes

多台linux服务器时间同步

CentOS6-ntpd

NTP是网络时间协议(Network Time Protocol)的缩写,它是用来同步网络上的各台计算机的时间的协议。它是美国David L. Mills博士设计实现的。

Linux操作系统维护的软件时间随着服务器的长时间运行会出现漂移,最终会越来越不准确。不准确的系统时间会对依赖时间的服务带来影响,例如数据库,认证等,因此需要维持一个相对准确的服务器时间。

目前,一般通过ntp服务来将本地时间和线上的时间服务保持同步,维护一个相对准确的系统时间

ntpd与ntpdate的区别

ntpd在实际同步时间时是一点点的校准过来时间的,最终把时间慢慢的校正对。而ntpdate不会考虑其他程序是否会阵痛,直接调整时间。

理想的做法是:
使用ntpd来校准时钟,而不是调整计算机时钟上的时间。
在计算机刚刚启动,但还没有启动很多服务的那个时候可以使用ntpdate同步时间。

直接用命令与时间服务器进行同步
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
ntpdate [-nv] [ IP/hostname]
# ntpdate -u 192.168.0.2
# ntpdate -u 10.11.0.35
# ntpdate -u time.ntp.org
# ntpdate -u ntp.sjtu.edu.cn >>/var/log/ntp.log 2>&1;hwclock -w

注意:若不加上-u参数, 会出现以下提示:no server suitable for synchronization found
-u:指定使用无特权的端口发送数据包,可以越过防火墙与主机同步;

阿里云时间服务器,授时信号来自GPS、北斗两套卫星信号,并配备原子钟守时,
以下7个域名提供服务,大家可以直接使用。
http://time1.aliyun.com
http://time2.aliyun.com
http://time3.aliyun.com
http://time4.aliyun.com
http://time5.aliyun.com
http://time6.aliyun.com
http://time7.aliyun.com

或者直接访问这个地址 time.pool.aliyun.com
# ntpdate -u time.pool.aliyun.com

可以加一个定时计划,定时同步
1. crontab -e
2. */5 * * * * /usr/sbin/ntpdate -u x.x.x.x
3. /etc/init.d/crond restart
自建ntpd 时间同步服务器
NTP通信协议原理
  1. 首先主机启动NTP。
  2. 客户端会向NTP服务器发送调整时间的message。
  3. 然后NTP server会送出当前的标准时间给client
  4. client接受来自server的时间后,会根据这个信息来调整自己的时间。这样就实现了网络对时。

NTP这个deamon采用了UDP 123端口。

远程服务器的层级(stratum):
由于NTP是层型结构,有顶端的服务器,多层的Relay Server再到客户端.
所以服务器从高到低级别可以设定为1-16.
为了减缓负荷和网络堵塞,原则上应该避免直接连接到级别为1的服务器的.

配置文件解析ntp.conf
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# For more information about this file, see the man pages
# ntp.conf(5), ntp_acc(5), ntp_auth(5), ntp_clock(5), ntp_misc(5), ntp_mon(5).
#系统时间与BIOS事件的偏差记录
driftfile /var/lib/ntp/drift

# Permit time synchronization with our time source, but do not
# permit the source to query or modify the service on this system.
restrict default nomodify notrap nopeer noquery

# Permit all access over the loopback interface. This could
# be tightened as well, but to do so would effect some of
# the administrative functions.
restrict 127.0.0.1
restrict ::1

# Hosts on local network are less restricted.
#restrict 192.168.1.0 mask 255.255.255.0 nomodify notrap

# Use public servers from the pool.ntp.org project.
# Please consider joining the pool (http://www.pool.ntp.org/join.html).
server 0.centos.pool.ntp.org iburst
server 1.centos.pool.ntp.org iburst
server 2.centos.pool.ntp.org iburst
server 3.centos.pool.ntp.org iburst

#broadcast 192.168.1.255 autokey # broadcast server
#broadcastclient # broadcast client
#broadcast 224.0.1.1 autokey # multicast server
#multicastclient 224.0.1.1 # multicast client
#manycastserver 239.255.254.254 # manycast server
#manycastclient 239.255.254.254 autokey # manycast client

#当外部时间不可用时,以本地(本机)时间作为服务时间
#本地时间以 127.127.1.0 表示 级别为10
# Undisciplined Local Clock. This is a fake driver intended for backup
# and when no outside source of synchronized time is available.
#server 127.127.1.0 # local clock
#fudge 127.127.1.0 stratum 10

# Enable public key cryptography.
#crypto

includefile /etc/ntp/crypto/pw

# Key file containing the keys and key identifiers used when operating
# with symmetric key cryptography.
keys /etc/ntp/keys

# Specify the key identifiers which are trusted.
#trustedkey 4 8 42

# Specify the key identifier to use with the ntpdc utility.
#requestkey 8

# Specify the key identifier to use with the ntpq utility.
#controlkey 8

# Enable writing of statistics records.
#statistics clockstats cryptostats loopstats peerstats

# Disable the monitoring facility to prevent amplification attacks using ntpdc
# monlist command when default restrict does not include the noquery flag. See
# CVE-2013-5211 for more details.
# Note: Monitoring will not be disabled with the limited restriction flag.
disable monitor

配置文件说明

restrict 控制相关权限。

语法为: restrict [ 客户端IP ] mask [ IP掩码 ] [参数]

其中IP地址也可以是default ,default 就是指所有的IP

参数有以下几个:

nomodify:客户端不能更改服务端的时间参数,但是客户端可以通过服务端进行网络校时。

notrust :拒絕沒有認證的用戶端

noquery :客户端不能使用ntpq,ntpc来查询ntp服务器,等于不提供校对时间服务

notrap :不提供trap远程登录功能,trap服务是一种远程时间日志服务

拒绝为匹配的主机提供模式 6 控制消息陷阱服务。陷阱服务是 ntpdq 控制消息协议的子系统,用于远程事件日志记录程序。

nopeer :用于阻止主机尝试与服务器对等

kod : 访问违规时发送 KoD 包,向不安全的访问者发送Kiss-Of-Death报文。

restrict -6 表示IPV6地址的权限设置

设定NTP主机来源(其中prefer表示优先主机)

语法为:server host [ key n ] [ version n ] [ prefer ] [ mode n ] [ minpoll n ] [ maxpoll n ] [ iburst ]

其中host是上层NTP服务器的IP地址或域名,随后所跟的参数解释如下所示:

◆ key: 表示所有发往服务器的报文包含有秘钥加密的认证信息,n是32位的整数,表示秘钥号。

◆ version: 表示发往上层服务器的报文使用的版本号,n默认是3,可以是1或者2。

◆ prefer: 优先使用。

◆ mode: 指定数据报文mode字段的值。

◆ minpoll: 指定与查询该服务器的最小时间间隔为2的n次方秒,n默认为6,范围为4-14。

◆ maxpoll: 指定与查询该服务器的最大时间间隔为2的n次方秒,n默认为10,范围为4-14。

◆ iburst: 当初始同步请求时,采用突发方式接连发送8个报文,时间间隔为2秒。

总体配置

注意 所有配置操作必须是root用户 。

在局域网内:

node21作为NTP Server;

node22,node23作为NTP Client与服务器进行时钟同步;

ntpd Server,用于和外部公共ntpd同步标准时间,同时作为内网的Server;

ntpd Client,用于与ntpd Server同步时间;

node21 192.168.100.21
node22 192.168.100.22
node23 192.168.100.23
具体步骤
  1. 检查ntp是否安装
1
2
3
4
5
[root@node21 ~]# rpm -qa|grep ntp
如果已安装显示
ntp-4.2.6p5-10.el6.centos.x86_64
fontpackages-filesystem-1.41-1.1.el6.noarch
ntpdate-4.2.6p5-10.el6.centos.x86_64
  1. 安装并配置自启动
1
2
3
4
5
yum -y install ntp
#启动ntp服务
systemctl start ntpd
#设置开机启动服务
systemctl enable ntpd.service
  1. 升版
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
#第一步:卸载老版本NTP,查找NTP安装包
rpm -qa | grep ntp

#第二步:卸载安装包
yum erase ntp-4.2.6p5-25.el7.centos.x86_64
yum erase ntpdate-4.2.6p5-25.el7.centos.x86_64

#第三步:安装新版本ntp-4.2.8p15(源码安装)
wget https://www.eecis.udel.edu/~ntp/ntp_spool/ntp4/ntp-4.2/ntp-4.2.8p15.tar.gz
tar -zxvf ntp-4.2.8p15.tar.gz
cd cd ntp-4.2.8p15
./configure
# Tip: echo $? 用来确认上一步是否成功执行
echo $?
make
echo $?
# 注意:make install 可能会覆盖一些文件,所以这一步要非常小心,默认会生成在 /usr/local/bin 中
make install
echo $?




#NTP安装过程如果报错,可以尝试执行下面的命令
rm –rf /usr/lib64/libssl.so
rm –rf /usr/lib64/libcrypto.so
ln -sv /usr/lib64/libssl.so.6 /usr/lib64/libssl.so
ln -sv /usr/lib64/libcrypto.so.1.0.1e /usr/lib64/libcrypto.so
  1. 防火墙配置

由于NTP服务需要使用到UDP端口号123,所以当系统的防火墙(Iptables)启动的情况下,必须开放UDP端口号123.

1
2
firewall-cmd --zone=public --add-port=123/udp --permanent
firewall-cmd --reload
  1. 配置ntp内网服务器

  2. 配置前先使用命令:ntpdate -u cn.pool.ntp.org,同步服务器

  3. ntpd Server:192.168.100.21 修改/etc/ntp.conf文件.源码安装的ntp服务/etc/下是没有ntp.conf配置文件的,需要先yum安装ntp服务把/etc/ntp.conf文件备份后,在yum –y remove ntp*删除掉安装的ntp

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# For more information about this file, see the man pages
# ntp.conf(5), ntp_acc(5), ntp_auth(5), ntp_clock(5), ntp_misc(5), ntp_mon(5).
driftfile /var/lib/ntp/drift
# Permit time synchronization with our time source, but do not
# permit the source to query or modify the service on this system.
restrict default nomodify notrap nopeer noquery

# Permit all access over the loopback interface. This could
# be tightened as well, but to do so would effect some of
# the administrative functions.
restrict 127.0.0.1
restrict ::1

# Hosts on local network are less restricted.
#restrict 192.168.1.0 mask 255.255.255.0 nomodify notrap
#### 添加部分-1###
# 允许内网其他机器同步时间,如果不添加该约束默认允许所有IP访问本机同步服务
restrict 192.168.100.0 mask 255.255.255.0 nomodify notrap
#### 添加部分-1###
# Use public servers from the pool.ntp.org project.
# Please consider joining the pool (http://www.pool.ntp.org/join.html).
#server 0.centos.pool.ntp.org iburst
#server 1.centos.pool.ntp.org iburst
#server 2.centos.pool.ntp.org iburst
#server 3.centos.pool.ntp.org iburst

#### 添加部分-2###
# 配置和上游标准时间同步
server 210.72.145.44 # 中国国家授时中心
server 133.100.11.8 #日本[福冈大学]
server 0.cn.pool.ntp.org
server 1.cn.pool.ntp.org
server 2.cn.pool.ntp.org
server 3.cn.pool.ntp.org

# 配置允许上游时间服务器主动修改本机(内网ntp Server)的时间
restrict 210.72.145.44 nomodify notrap noquery
restrict 133.100.11.8 nomodify notrap noquery
restrict 0.cn.pool.ntp.org nomodify notrap noquery
restrict 1.cn.pool.ntp.org nomodify notrap noquery
restrict 2.cn.pool.ntp.org nomodify notrap noquery
restrict 3.cn.pool.ntp.org nomodify notrap noquery

# 确保localhost有足够权限,使用没有任何限制关键词的语法。
# 外部时间服务器不可用时,以本地时间作为时间服务。
# 注意:这里不能改,必须使用127.127.1.0,否则会导致无法
#在ntp客户端运行ntpdate serverIP,出现no server suitable for synchronization found的错误。
#在ntp客户端用ntpdate –d serverIP查看,发现有“Server dropped: strata too high”的错误,并且显示“stratum 16”。而正常情况下stratum这个值得范围是“0~15”。
#这是因为NTP server还没有和其自身或者它的server同步上。
#以下的定义是让NTP Server和其自身保持同步,如果在ntp.conf中定义的server都不可用时,将使用local时间作为ntp服务提供给ntp客户端。
#下面这个配置,建议NTP Client关闭,建议NTP Server打开。因为Client如果打开,可能导致NTP自动选择合适的最近的NTP Server、也就有可能选择了LOCAL作为Server进行同步,而不与远程Server进行同步。

server 127.127.1.0 # local clock
fudge 127.127.1.0 stratum 10

#### 添加部分-2###
#broadcast 192.168.1.255 autokey # broadcast server
#broadcastclient # broadcast client
#broadcast 224.0.1.1 autokey # multicast server
#multicastclient 224.0.1.1 # multicast client
#manycastserver 239.255.254.254 # manycast server
#manycastclient 239.255.254.254 autokey # manycast client

# Enable public key cryptography.
#crypto

includefile /etc/ntp/crypto/pw

# Key file containing the keys and key identifiers used when operating
# with symmetric key cryptography.
keys /etc/ntp/keys

# Specify the key identifiers which are trusted.
#trustedkey 4 8 42

# Specify the key identifier to use with the ntpdc utility.
#requestkey 8

# Specify the key identifier to use with the ntpq utility.
#controlkey 8

# Enable writing of statistics records.
#statistics clockstats cryptostats loopstats peerstats

# Disable the monitoring facility to prevent amplification attacks using ntpdc
# monlist command when default restrict does not include the noquery flag. See
# CVE-2013-5211 for more details.
# Note: Monitoring will not be disabled with the limited restriction flag.
disable monitor
  1. 重启服务端ntpd服务并查看同步状态
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@node21 ~]# systemctl restart ntpd
[root@node21 ~]# ntpq -p
remote refid st t when poll reach delay offset jitter
==============================================================================
210.72.145.44 .INIT. 16 u - 64 0 0.000 0.000 0.000
clock.tl.fukuok .INIT. 16 u - 64 0 0.000 0.000 0.000
gus.buptnet.edu 10.3.8.150 5 u 53 64 7 113.234 -29.011 5.500
cn.ntp.faelix.n 185.134.196.169 2 u 54 64 7 154.859 -67.243 18.652
static-5-103-13 .GPS. 1 u 53 64 7 406.416 -92.420 21.929
*LOCAL(0) .LOCL. 10 l 60 64 7 0.000 0.000 0.000
[root@node21 ~]# ntpstat
synchronised to NTP server (5.103.139.163) at stratum 2
time correct to within 456 ms
polling server every 64 s
  1. 配置客户端

node22,node23为客户端。

  1. 检查ntp是否安装,以及是否设置了自启动,参考ntpd Server的ntp安装检查。
  2. 修改/etc/ntp.conf文件:
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# For more information about this file, see the man pages
# ntp.conf(5), ntp_acc(5), ntp_auth(5), ntp_clock(5), ntp_misc(5), ntp_mon(5).

driftfile /var/lib/ntp/drift

# Permit time synchronization with our time source, but do not
# permit the source to query or modify the service on this system.
restrict default nomodify notrap nopeer noquery

# Permit all access over the loopback interface. This could
# be tightened as well, but to do so would effect some of
# the administrative functions.
restrict 127.0.0.1
restrict ::1

# Hosts on local network are less restricted.
#restrict 192.168.1.0 mask 255.255.255.0 nomodify notrap
###### 修改部分 #########
# Use public servers from the pool.ntp.org project.
# Please consider joining the pool (http://www.pool.ntp.org/join.html).
#server 0.centos.pool.ntp.org iburst
#server 1.centos.pool.ntp.org iburst
#server 2.centos.pool.ntp.org iburst
#server 3.centos.pool.ntp.org iburst

#配置上游时间服务器为本地的ntpd Server服务器
server 192.168.100.21

# 配置允许上游时间服务器主动修改本机的时间
restrict 192.168.100.21 nomodify notrap noquery

#下面这个配置,建议NTP Client关闭,建议NTP Server打开。因为Client如果打开,可能导致NTP自动选择合适的最近的NTP Server、也就有可能选择了LOCAL作为Server进行同步,而不与远程Server进行同步。
#server 127.127.1.0 # local clock
#fudge 127.127.1.0 stratum 10

###### 修改部分 #########

#broadcast 192.168.1.255 autokey # broadcast server
#broadcastclient # broadcast client
#broadcast 224.0.1.1 autokey # multicast server
#multicastclient 224.0.1.1 # multicast client
#manycastserver 239.255.254.254 # manycast server
#manycastclient 239.255.254.254 autokey # manycast client

# Enable public key cryptography.
#crypto
includefile /etc/ntp/crypto/pw

# Key file containing the keys and key identifiers used when operating
# with symmetric key cryptography.
keys /etc/ntp/keys

# Specify the key identifiers which are trusted.
#trustedkey 4 8 42

# Specify the key identifier to use with the ntpdc utility.
#requestkey 8

# Specify the key identifier to use with the ntpq utility.
#controlkey 8

# Enable writing of statistics records.
#statistics clockstats cryptostats loopstats peerstats

# Disable the monitoring facility to prevent amplification attacks using ntpdc
# monlist command when default restrict does not include the noquery flag. See
# CVE-2013-5211 for more details.
# Note: Monitoring will not be disabled with the limited restriction flag.
disable monitor
  1. 重启客户端ntpd服务并查看状态
1
2
3
4
5
[root@node22 ~]# systemctl restart ntpd
[root@node22 ~]# ntpq -p
remote refid st t when poll reach delay offset jitter
==============================================================================
node21 LOCAL(0) 11 u 2 64 0 0.000 0.000 0.000

linux - How to keep the time on multiple servers in sync - Server Fault

CentOS7-Chrony

chrony是CentOS7.x上自带的时间同步软件

CentOS 7版本中使用Chrony工具实现本地时间与标准时间同步。与CentOS 6版本中的NTP服务不同,Chrony可以更快更准确地同步系统时钟,最大程度的减少时间和频率误差。Chrony包含了两个核心程序:

  • chronyd是后台运行的守护进程。用于调整内核中运行的系统时钟和时钟服务器同步。它确定计算机增减时间的比率,并对此进行修正。
  • chronyc提供了一个用户界面,用于监控性能并进行多样化的配置。它可以在chronyd控制的服务器上工作;也可以在一台不同的远程服务器上工作
chrony的优势

  更快的同步只需要数分钟而非数小时时间,从而最大程度减少了时间和频率误差,这对于并非全天 24 小时运行的台式计算机或系统而言非常有用。

  能够更好地响应时钟频率的快速变化,这对于具备不稳定时钟的虚拟机或导致时钟频率发生变化的节能技术而言非常有用。

  在初始同步后,它不会停止时钟,以防对需要系统时间保持单调的应用程序造成影响。

  在应对临时非对称延迟时(例如,在大规模下载造成链接饱和时)提供了更好的稳定性。

  无需对服务器进行定期轮询,因此具备间歇性网络连接的系统仍然可以快速同步时钟。

操作
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# yum install -y chrony     -->安装服务
# systemctl start chronyd.service -->启动服务
# systemctl enable chronyd.service -->设置开机自启动,默认是enable的

$ firewall-cmd --add-service=ntp --permanent
$ firewall-cmd --reload

# 运行以下命令查看本机时间同步状态,用于验证服务是否已启动。
chronyc tracking


#检查ntp源服务器状态 查看同步状态
[root@localhost ~]# chronyc sourcestats
210 Number of sources = 4
Name/IP Address NP NR Span Frequency Freq Skew Offset Std Dev
==============================================================================
time.cloudflare.com 15 10 27h +0.042 0.026 -7204us 1032us
tock.ntp.infomaniak.ch 14 7 224m +0.024 0.706 -4643us 2638us
ntp1.flashdance.cx 49 25 14h +0.039 0.136 -19ms 3702us
111.230.189.174 30 18 10h +0.001 0.080 +302ns 1200us
[root@localhost ~]#
#查看ntp详细的同步状态
[root@localhost ~]# chronyc sources -v
210 Number of sources = 4

.-- Source mode '^' = server, '=' = peer, '#' = local clock.
/ .- Source state '*' = current synced, '+' = combined , '-' = not combined,
| / '?' = unreachable, 'x' = time may be in error, '~' = time too variable.
|| .- xxxx [ yyyy ] +/- zzzz
|| Reachability register (octal) -. | xxxx = adjusted offset,
|| Log2(Polling interval) --. | | yyyy = measured offset,
|| \ | | zzzz = estimated error.
|| | | \
MS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
^- time.cloudflare.com 3 10 377 396m -5932us[-4919us] +/- 104ms
^- tock.ntp.infomaniak.ch 1 10 377 509 -297us[ -206us] +/- 70ms
^- ntp1.flashdance.cx 2 10 377 522 -32ms[ -32ms] +/- 183ms
^* 111.230.189.174 2 10 175 466 -239us[ -148us] +/- 52ms
[root@localhost ~]#

##设置时区
[root@testserver ~]# timedatectl
Local time: Mon 2021-10-25 14:09:44 CST
Universal time: Mon 2021-10-25 06:09:44 UTC
RTC time: Mon 2021-10-25 06:09:44
Time zone: Asia/Shanghai (CST, +0800)
NTP enabled: yes
NTP synchronized: yes
RTC in local TZ: no
DST active: n/a
[root@testserver ~]#
[root@testserver ~]# timedatectl list-timezones | grep -E "Asia/S.*"
Asia/Sakhalin
Asia/Samarkand
Asia/Seoul
Asia/Shanghai
Asia/Singapore
Asia/Srednekolymsk
[root@testserver ~]# timedatectl set-timezone Asia/Shanghai
[root@testserver ~]#
#设置完时区后,强制同步下系统时钟:
[root@testserver ~]#chronyc -a makestep
200 OK
配置文件

chrony服务使用的配置文件为/etc/chrony.conf.其配置内容格式和ntpd服务基本相似

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
41
42
43
44
45
46
47
48
49
[root@localhost ~]# cat /etc/chrony.conf
# Use public servers from the pool.ntp.org project.
# Please consider joining the pool (http://www.pool.ntp.org/join.html).
server 0.centos.pool.ntp.org iburst
server 1.centos.pool.ntp.org iburst
server 2.centos.pool.ntp.org iburst
server 3.centos.pool.ntp.org iburst

# Record the rate at which the system clock gains/losses time.
# 根据实际时间计算出服务器增减时间的比率,然后记录到一个文件中,在系统重启后为系统做出最佳时间补偿调整。
driftfile /var/lib/chrony/drift

# Allow the system clock to be stepped in the first three updates
# if its offset is larger than 1 second.
# chronyd根据需求减慢或加速时间调整,
# 在某些情况下系统时钟可能漂移过快,导致时间调整用时过长。
# 该指令强制chronyd调整时期,大于某个阀值时步进调整系统时钟。
# 只有在因chronyd启动时间超过指定的限制时(可使用负值来禁用限制)没有更多时钟更新时才生效。
makestep 1.0 3

# Enable kernel synchronization of the real-time clock (RTC).
# 将启用一个内核模式,在该模式中,系统时间每11分钟会拷贝到实时时钟(RTC)。
rtcsync

# Enable hardware timestamping on all interfaces that support it.
# 通过使用hwtimestamp指令启用硬件时间戳
#hwtimestamp *

# Increase the minimum number of selectable sources required to adjust
# the system clock.
#minsources 2

# Allow NTP client access from local network.
# 指定一台主机、子网,或者网络以允许或拒绝NTP连接到扮演时钟服务器的机器
#allow 192.168.0.0/16
#deny 192.168/16

# Serve time even if not synchronized to a time source.
#local stratum 10

# Specify file containing keys for NTP authentication.
#keyfile /etc/chrony.keys

# Specify directory for log files.
logdir /var/log/chrony

# Select which information is logged.
#log measurements statistics tracking
[root@localhost ~]#
配置参数说明
参数 参数说明
server 该参数可以多次用于添加时钟服务器,必须以”server “格式使用。一般而言,你想添加多少服务器,就可以添加多少服务器
stratumweight stratumweight指令设置当chronyd从可用源中选择同步源时,每个层应该添加多少距离到同步距离。默认情况下,CentOS中设置为0,让chronyd在选择源时忽略源的层级
driftfile chronyd程序的主要行为之一,就是根据实际时间计算出计算机增减时间的比率,将它记录到一个文件中是最合理的,它会在重启后为系统时钟作出补偿,甚至可能的话,会从时钟服务器获得较好的估值
rtcsync rtcsync指令将启用一个内核模式,在该模式中,系统时间每11分钟会拷贝到实时时钟(RTC)
allow/deny 这里你可以指定一台主机、子网,或者网络以允许或拒绝NTP连接到扮演时钟服务器的机器
cmdallow/cmddeny 跟上面相类似,只是你可以指定哪个IP地址或哪台主机可以通过chronyd使用控制命令
bindcmdaddress 该指令允许你限制chronyd监听哪个网络接口的命令包(由chronyc执行)。该指令通过cmddeny机制提供了一个除上述限制以外可用的额外的访问控制等级
makestep 通常,chronyd将根据需求通过减慢或加速时钟,使得系统逐步纠正所有时间偏差。在某些特定情况下,系统时钟可能会漂移过快,导致该调整过程消耗很长的时间来纠正系统时钟。该指令强制chronyd在调整期大于某个阀值时步进调整系统时钟,但只有在因为chronyd启动时间超过指定限制(可使用负值来禁用限制),没有更多时钟更新时才生效
服务器集群之间的系统时间同步

在生产环境中,其网络都是内网结构,那么内网如何保证服务器之间的时间同步呢?其实这个问题很简单,只需要搭建一台内网时间服务器,然后让所有计算机都到服务端(10.28.204.66)去同步时间即可。

具体操作:在服务端注释以下内容:

1
2
3
4
5
6
7
8
#server 0.centos.pool.ntp.org iburst
#server 1.centos.pool.ntp.org iburst
#server 2.centos.pool.ntp.org iburst
#server 3.centos.pool.ntp.org iburst

#并添加以下内容:(表示与本机同步时间,IP与服务器本机地址相同)
server 10.28.204.66 iburst
#这样我们需求的一台内网时间服务器已经配置完毕

具体操作:在客户端注释以下内容:

1
2
#同样在客户端注释掉其他server,并在客户端(10.28.204.65)添加以下:
server 10.28.204.66 iburst

到此已经完成系统时间的同步。如有多台机器,操作也是如此。

最后需要注意的是,配置完/etc/chrony.conf后,需重启chrony服务,否则可能会不生效。

定时任务

crond与crontab

cron是任务的意思,tab 表示table。crontab 可以理解为,任务时间表。 crontab 命令是用来让计算机替我们执行周期性任务,比如要在每周二的凌晨五点重启服务器,每天凌晨执行一次备份任务。主要管理以分钟、小时、日、月、周,为周期来执行定期任务。守护进程 crond 为 crontab 命令提供服务。

crond 是linux下用来周期性的执行某种任务或等待处理某些事件的一个守护进程,与windows下的计划任务类似,当安装完成操作系统后,默认会安装此服务 工具,并且会自动启动crond进程,crond进程每分钟会定期检查是否有要执行的任务,如果有要执行的任务,则自动执行该任务。

crontab 的白名单与黑名单

在系统的 /etc目录下可能会有两个使用 crontab 的限制文件。

  • 白名单/etc/cron.allow,用来记录那些用户可以使用 crontab
  • 黑名单 /ect/cron.deny,用来限制那些不用户不能使用 crontab,黑名单对root 是无效的。

当两个文件都存在时,以 白名单为准。当两个文件都不存在时,只有root可以。一般系统中只有黑名单文件,因为每个用户所执行的定时任务都与他自身的用户权限有关

任务调度

Linux下的任务调度分为两类,系统任务调度和用户任务调度。

  • 系统任务调度:系统周期性所要执行的工作,比如写缓存数据到硬盘、日志清理等。在/etc目录下有一个crontab文件,这个就是系统任务调度的配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[hqc@localhost hqctest]$ cat /etc/crontab
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
# MAILTO变量指定了crond的任务执行信息将通过电子邮件发送给root用户,如果MAILTO变量的值为空,则表示不发送任务 执行信息给用户
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
  • 用户任务调度:用户定期要执行的工作,比如用户数据备份、定时邮件提醒等。用户可以使用 crontab 工具来定制自己的计划任务。所有用户定义的crontab 文件都被保存在 /var/spool/cron目录中。其文件名与用户名一致。

cron表达式

1
2
3
4
5
6
7
8
# 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
符号 含义 举例
* 表示任意时间的意思 比如 “* * * * * 任务” 就代表每分钟执行一次
逗号“,” 代表不连续的时间 比如 “ 0 1,3 * * * 任务” 就代表每天的1点整,3点整分别都执行一次
短杠“-” 代表连续的时间范围 比如 “0 2 * * 1-3 任务” 就代表每周一到周三的凌晨2点0分执行任务
*/n 代表每隔多久执行一次。 比如 “*/30 * * * * 任务” 就代表每三十分钟执行一次任务

crontab 时间的练习

1、 30 21 * * * 任务 是什么意思?

答:每天的 21 点 30 执行任务。

2、0 20 * * 1 任务是什么意思?

答:每周一的 20 点 00 分执行任务。

3、0 8 1,15,25 * * 任务是什么意思?

答:每月1 号 ,15 号,25号的8 点 00 分 执行任务。

4、 */10 3 * * * 任务 是什么意思?

答:每天凌晨 3 点钟 每个十分钟执行一次任务。

5、0 1 1,10 * 2 任务 是什么意思?

答:每月的周二或每月的 1号 ,10号 的凌晨 1点00分执行任务。这里并不是每月的1号 ,10号并且还要是周二才执行。

实例1:每1分钟执行一次command
命令:
* * * * * command

实例2:每小时的第3和第15分钟执行
命令:
3,15 * * * * command

实例3:在上午8点到11点的第3和第15分钟执行
命令:
3,15 8-11 * * * command

实例4:每隔两天的上午8点到11点的第3和第15分钟执行
命令:
3,15 8-11 */2 * * command

实例5:每个星期一的上午8点到11点的第3和第15分钟执行
命令:
3,15 8-11 * * 1 command

实例6:每晚的21:30重启smb
命令:
30 21 * * * /etc/init.d/smb restart

实例7:每月1、10、22日的4 : 45重启smb
命令:
45 4 1,10,22 * * /etc/init.d/smb restart

实例8:每周六、周日的1 : 10重启smb
命令:
10 1 * * 6,0 /etc/init.d/smb restart

实例9:每天18 : 00至23 : 00之间每隔30分钟重启smb
命令:
0,30 18-23 * * * /etc/init.d/smb restart

实例10:每星期六的晚上11 : 00 pm重启smb
命令:
0 23 * * 6 /etc/init.d/smb restart

实例11:每一小时重启smb
命令:
* */1 * * * /etc/init.d/smb restart

实例12:晚上11点到早上7点之间,每隔一小时重启smb
命令:
* 23-7/1 * * * /etc/init.d/smb restart

实例13:每月的4号与每周一到周三的11点重启smb
命令:
0 11 4 * mon-wed /etc/init.d/smb restart

实例14:一月一号的4点重启smb
命令:
0 4 1 jan * /etc/init.d/smb restart

实例15:每小时执行/etc/cron.hourly目录内的脚本
命令:
01 * * * * root run-parts /etc/cron.hourly
说明:
run-parts这个参数了,如果去掉这个参数的话,后面就可以写要运行的某个脚本名,而不是目录名了

创建过程

  • 创建文件,写入cron表达式,然后执行crontab rootcron. 将新创建文件的一个副本已经被放在/var/spool/cron目录中,文件名就是用户名(即root)
  • 直接执行crontab -e直接vi编辑cron表达式。如果修改了某些条目或添加了新的条目,那么在保存该文件时, cron会对其进行必要的完整性检查。如果其中的某个域出现了超出允许范围的值,它会提示你

cron 注意事项

  • 六个选项都不能为空,必须填写,如果不确定可以使用 * 表示任意时间。

  • crontab 定时任务,最小时间是分钟,最大是月,不能指定多少秒或多少年。

  • 在写时间时,尽量不要把日期和星期写在一起,都是用天表示单位,容易混乱。

  • 定时任务中,最好使用绝对路径,因为 进程可能有自己的环境变量。

  • 脚本执行要用到java或其他环境变量时,通过source命令引入环境变量

  • 新创建的cron job,不会马上执行,至少要过2分钟才执行。如果重启cron则马上执行。

  • 当crontab突然失效时,可以尝试/etc/init.d/crond restart解决问题。或者查看日志看某个job有没有执行/报错tail -f /var/log/cron。

  • 千万别乱运行crontab -r。它从Crontab目录(/var/spool/cron)中删除用户的Crontab文件。删除了该用户的所有crontab都没了。

crond服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
安装crontab:

yum install crontabs

服务操作说明:

/sbin/service crond start //启动服务

/sbin/service crond stop //关闭服务

/sbin/service crond restart //重启服务

/sbin/service crond reload //重新载入配置

/sbin/service crond status //启动服务


查看crontab服务是否已设置为开机启动,执行命令:

ntsysv

加入开机自动启动:

chkconfig –level 35 crond on

设置防火墙

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
firewall-cmd --zone=public --add-port=3306/tcp --permanent
## 开启3306端口后,workbench或naivcat 就能连接到MySQL数据库了
firewall-cmd --reload

firewall-cmd --state ##查看防火墙状态,是否是running
firewall-cmd --reload ##重新载入配置,比如添加规则之后,需要执行此命令
firewall-cmd --get-zones ##列出支持的zone
firewall-cmd --get-services ##列出支持的服务,在列表中的服务是放行的
firewall-cmd --query-service ftp ##查看ftp服务是否支持,返回yes或者no
firewall-cmd --add-service=ftp ##临时开放ftp服务
firewall-cmd --add-service=ftp --permanent ##永久开放ftp服务
firewall-cmd --remove-service=ftp --permanent ##永久移除ftp服务
firewall-cmd --add-port=80/tcp --permanent ##永久添加80端口
iptables -L -n ##查看规则,这个命令是和iptables的相同的
man firewall-cmd ##查看帮助
systemctl status firewalld.service ##查看防火墙状态
systemctl [start|stop|restart] firewalld.service ##启动|关闭|重新启动 防火墙

##查询端口号80 是否开启
firewall-cmd --query-port=80/tcp

Linux下重复执行命令(主要用于对比)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[oracle@prodserver download]$ watch -h

Usage:
watch [options] command

Options:
-b, --beep beep if command has a non-zero exit
-c, --color interpret ANSI color and style sequences
-d, --differences[=<permanent>]
highlight changes between updates
-e, --errexit exit if command has a non-zero exit
-g, --chgexit exit when output from command changes
-n, --interval <secs> seconds to wait between updates
-p, --precise attempt run command in precise intervals
-t, --no-title turn off header
-x, --exec pass command to exec instead of "sh -c"

-h, --help display this help and exit
-v, --version output version information and exit

For more details see watch(1).
[oracle@prodserver download]$ watch -n 1 -d 'ntpq -p && date -I'ns' && ssh hqc2@10.115.13.147 date -I'ns' && ssh hqc3@10.115.13.146 date -I'ns' '

日志排查

1
2
3
4
5
6
7
8
9
10
# 查看 systemd 的错误日志,-p 支持 emerg alert err crit warning notice info debug 等值
journalctl -p err
# 查看指定服务的日志
journalctl -u httpd
# 查看内核日志
journalctl -k
# 查看脚本的日志
journalctl /usr/bin/bash
# 查看指定用户的日志
journalctl UID=33 --since today

linux 开发部署

开发部署1

常见问题

处理因系统原因引起的文件中特殊字符的问题

1
2
3
4
5
6
7
8
9
10
11
12
# 可以转换为该系统下的文件格式
cat file.sh > file.sh_bak

# 先将file.sh中文件内容复制下来然后运行, 然后粘贴内容, 最后ctrl + d 保存退出
cat > file1.sh

# 在vim中通过如下设置文件编码和文件格式
:set fileencodings=utf-8 ,然后 w (存盘)一下即可转化为 utf8 格式,
:set fileformat=unix

# 在mac下使用dos2unix进行文件格式化
find . -name "*.sh" | xargs dos2unix

原理

系统启动过程

Linux系统的启动过程分为如下几个阶段:

  1. 开机自检:打开电源,BIOS进行硬件自检
  2. 引导加载:自检通过后,进入MBR引导加载程序(MBR是硬盘中第一个扇区的前512个字节, 称为 main boot record)
  3. 内核初始化:加载内核(Kernel)代码,即读入 /boot 目录下的内核文件,监测设备并加载设备驱动程序
  4. Systemd初始化(替代init),获取系统控制权
    • 执行Systemd程序,Systemd是一个管理进程的进程程序,也是操作系统的第一个进程,其PID=1
    • 读取 /etc/systemd 下的配置文件
    • 读取 /etc/systemd/system/default.target 下的运行级别文件
    • 执行 /etc/rc.d/rc.local 文件中的程序

2-4 是由GRUB(Grand Unified Bootloader)负责的。其中GRUB boot loader 代码的一小部分(子集)被写入MBR,其余部分存储在/boot分区中

  1. Systemd 执行系统初始化
  • 设置主机名
  • 初始化网络
  • 基于配置初始化 SElinux
  • 显示欢迎标语
  • 基于内核参数初始化硬件
  • 加载文件系统
  • 清除 /var 中的目录
  • 启动交换分区
  1. 建立终端:系统打开6个终端,以便用户登录系统。

  2. 用户登录系统:用户登录使用Linux

参考链接

Vim教程 (aliyun.com)

linux 下后台运行python脚本

在线生成cron表达式

Typora

Markdown For Typora

Overview

Markdown is created by Daring Fireball; the original guideline is here. Its syntax, however, varies between different parsers or editors. Typora is using GitHub Flavored Markdown.

[toc]

Block Elements

Paragraph and line breaks

A paragraph is simply one or more consecutive lines of text. In markdown source code, paragraphs are separated by two or more blank lines. In Typora, you only need one blank line (press Return once) to create a new paragraph.

Press Shift + Return to create a single line break. Most other markdown parsers will ignore single line breaks, so in order to make other markdown parsers recognize your line break, you can leave two spaces at the end of the line, or insert <br/>.

Headers

Headers use 1-6 hash (#) characters at the start of the line, corresponding to header levels 1-6. For example:

1
2
3
4
5
# This is an H1

## This is an H2

###### This is an H6

In Typora, input ‘#’s followed by title content, and press Return key will create a header.

Blockquotes

Markdown uses email-style > characters for block quoting. They are presented as:

1
2
3
4
5
6
7
> This is a blockquote with two paragraphs. This is first paragraph.
>
> This is second pragraph. Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.



> This is another blockquote with one paragraph. There is three empty line to seperate two blockquote.

In Typora, inputting ‘>’ followed by your quote contents will generate a quote block. Typora will insert a proper ‘>’ or line break for you. Nested block quotes (a block quote inside another block quote) by adding additional levels of ‘>’.

Lists

Input * list item 1 will create an unordered list - the * symbol can be replace with + or -.

Input 1. list item 1 will create an ordered list - their markdown source code is as follows:

1
2
3
4
5
6
7
8
9
## un-ordered list
* Red
* Green
* Blue

## ordered list
1. Red
2. Green
3. Blue

Task List

Task lists are lists with items marked as either [ ] or [x] (incomplete or complete). For example:

1
2
3
4
5
- [ ] a task list item
- [ ] list syntax required
- [ ] normal **formatting**, @mentions, #1234 refs
- [ ] incomplete
- [x] completed

You can change the complete/incomplete state by clicking on the checkbox before the item.

(Fenced) Code Blocks

Typora only supports fences in GitHub Flavored Markdown. Original code blocks in markdown are not supported.

Using fences is easy: Input ``` and press return. Add an optional language identifier after ``` and we’ll run it through syntax highlighting:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Here's an example:

```js
function test() {
console.log("notice the blank line before this function?");
}
```

syntax highlighting:
```ruby
require 'redcarpet'
markdown = Redcarpet.new("Hello World!")
puts markdown.to_html
```

Math Blocks

You can render LaTeX mathematical expressions using MathJax.

To add a mathematical expression, input $$ and press the ‘Return’ key. This will trigger an input field which accepts Tex/LaTex source. For example:

$$
\mathbf{V}_1 \times \mathbf{V}_2 = \begin{vmatrix}
\mathbf{i} & \mathbf{j} & \mathbf{k} \
\frac{\partial X}{\partial u} & \frac{\partial Y}{\partial u} & 0 \
\frac{\partial X}{\partial v} & \frac{\partial Y}{\partial v} & 0 \
\end{vmatrix}
$$

In the markdown source file, the math block is a LaTeX expression wrapped by a pair of ‘$$’ marks:

1
2
3
4
5
6
7
$$
\mathbf{V}_1 \times \mathbf{V}_2 = \begin{vmatrix}
\mathbf{i} & \mathbf{j} & \mathbf{k} \\
\frac{\partial X}{\partial u} & \frac{\partial Y}{\partial u} & 0 \\
\frac{\partial X}{\partial v} & \frac{\partial Y}{\partial v} & 0 \\
\end{vmatrix}
$$

You can find more details here.

Tables

Input | First Header | Second Header | and press the return key. This will create a table with two columns.

After a table is created, putting focus on that table will open up a toolbar for the table where you can resize, align, or delete the table. You can also use the context menu to copy and add/delete individual columns/rows.

The full syntax for tables is described below, but it is not necessary to know the full syntax in detail as the markdown source code for tables is generated automatically by Typora.

In markdown source code, they look like:

1
2
3
4
| First Header  | Second Header |
| ------------- | ------------- |
| Content Cell | Content Cell |
| Content Cell | Content Cell |

You can also include inline Markdown such as links, bold, italics, or strikethrough in the table.

Finally, by including colons (:) within the header row, you can define text in that column to be left-aligned, right-aligned, or center-aligned:

1
2
3
4
5
| Left-Aligned  | Center Aligned  | Right Aligned |
| :------------ |:---------------:| -----:|
| col 3 is | some wordy text | $1600 |
| col 2 is | centered | $12 |
| zebra stripes | are neat | $1 |

A colon on the left-most side indicates a left-aligned column; a colon on the right-most side indicates a right-aligned column; a colon on both sides indicates a center-aligned column.

Footnotes

1
2
3
You can create footnotes like this[^footnote].

[^footnote]: Here is the *text* of the **footnote**.

will produce:

You can create footnotes like this[^footnote].

[^footnote]: Here is the text of the footnote.

Hover over the ‘footnote’ superscript to see content of the footnote.

Horizontal Rules

Inputting *** or --- on a blank line and pressing return will draw a horizontal line.


YAML Front Matter

Typora now supports YAML Front Matter. Input --- at the top of the article and then press Return to introduce a metadata block. Alternatively, you can insert a metadata block from the top menu of Typora.

Table of Contents (TOC)

Input [toc] and press the Return key. This will create a “Table of Contents” section. The TOC extracts all headers from the document, and its contents are updated automatically as you add to the document.

Span Elements

Span elements will be parsed and rendered right after typing. Moving the cursor in middle of those span elements will expand those elements into markdown source. Below is an explanation of the syntax for each span element.

Markdown supports two styles of links: inline and reference.

In both styles, the link text is delimited by [square brackets].

To create an inline link, use a set of regular parentheses immediately after the link text’s closing square bracket. Inside the parentheses, put the URL where you want the link to point, along with an optional title for the link, surrounded in quotes. For example:

1
2
3
This is [an example](http://example.com/ "Title") inline link.

[This link](http://example.net/) has no title attribute.

will produce:

This is an example inline link. (<p>This is <a href="http://example.com/" title="Title">)

This link has no title attribute. (<p><a href="http://example.net/">This link</a> has no)

You can set the href to headers, which will create a bookmark that allow you to jump to that section after clicking. For example:

Command(on Windows: Ctrl) + Click This link will jump to header Block Elements. To see how to write that, please move cursor or click that link with key pressed to expand the element into markdown source.

Reference-style links use a second set of square brackets, inside which you place a label of your choosing to identify the link:

1
2
3
4
5
This is [an example][id] reference-style link.

Then, anywhere in the document, you define your link label on a line by itself like this:

[id]: http://example.com/ "Optional Title Here"

In Typora, they will be rendered like so:

This is an example reference-style link.

The implicit link name shortcut allows you to omit the name of the link, in which case the link text itself is used as the name. Just use an empty set of square brackets — for example, to link the word “Google” to the google.com web site, you could simply write:

1
2
3
4
[Google][]
And then define the link:

[Google]: http://google.com/

In Typora, clicking the link will expand it for editing, and command+click will open the hyperlink in your web browser.

URLs

Typora allows you to insert URLs as links, wrapped by <brackets>.

<i@typora.io> becomes i@typora.io.

Typora will also automatically link standard URLs. e.g: www.google.com.

Images

Images have similar syntax as links, but they require an additional ! char before the start of the link. The syntax for inserting an image looks like this:

1
2
3
![Alt text](/path/to/img.jpg)

![Alt text](/path/to/img.jpg "Optional title")

You are able to use drag & drop to insert an image from an image file or your web browser. You can modify the markdown source code by clicking on the image. A relative path will be used if the image that is added using drag & drop is in same directory or sub-directory as the document you’re currently editing.

If you’re using markdown for building websites, you may specify a URL prefix for the image preview on your local computer with property typora-root-url in YAML Front Matters. For example, input typora-root-url:/User/Abner/Website/typora.io/ in YAML Front Matters, and then ![alt](/blog/img/test.png) will be treated as ![alt](file:///User/Abner/Website/typora.io/blog/img/test.png) in Typora.

You can find more details here.

Emphasis

Markdown treats asterisks (*) and underscores (_) as indicators of emphasis. Text wrapped with one * or _ will be wrapped with an HTML <em> tag. E.g:

1
2
3
*single asterisks*

_single underscores_

output:

single asterisks

single underscores

GFM will ignore underscores in words, which is commonly used in code and names, like this:

wow_great_stuff

do_this_and_do_that_and_another_thing.

To produce a literal asterisk or underscore at a position where it would otherwise be used as an emphasis delimiter, you can backslash escape it:

1
\*this text is surrounded by literal asterisks\*

Typora recommends using the * symbol.

Strong

A double * or _ will cause its enclosed contents to be wrapped with an HTML <strong> tag, e.g:

1
2
3
**double asterisks**

__double underscores__

output:

double asterisks

double underscores

Typora recommends using the ** symbol.

Code

To indicate an inline span of code, wrap it with backtick quotes (`). Unlike a pre-formatted code block, a code span indicates code within a normal paragraph. For example:

1
Use the `printf()` function.

will produce:

Use the printf() function.

Strikethrough

GFM adds syntax to create strikethrough text, which is missing from standard Markdown.

~~Mistaken text.~~ becomes Mistaken text.

Underlines

Underline is powered by raw HTML.

<u>Underline</u> becomes Underline.

Emoji :smile:

Input emoji with syntax :smile:.

User can trigger auto-complete suggestions for emoji by pressing ESC key, or trigger it automatically after enabling it on preference panel. Also, inputting UTF-8 emoji characters directly is also supported by going to Edit -> Emoji & Symbols in the menu bar (macOS).

Inline Math

To use this feature, please enable it first in the Preference Panel -> Markdown Tab. Then, use $ to wrap a TeX command. For example: $\lim_{x \to \infty} \exp(-x) = 0$ will be rendered as LaTeX command.

To trigger inline preview for inline math: input “$”, then press the ESC key, then input a TeX command.

You can find more details here.

Subscript

To use this feature, please enable it first in the Preference Panel -> Markdown Tab. Then, use ~ to wrap subscript content. For example: H~2~O, X~long\ text~/

Superscript

To use this feature, please enable it first in the Preference Panel -> Markdown Tab. Then, use ^ to wrap superscript content. For example: X^2^.

Highlight

To use this feature, please enable it first in the Preference Panel -> Markdown Tab. Then, use == to wrap highlight content. For example: ==highlight==.

HTML

You can use HTML to style content what pure Markdown does not support. For example, use <span style="color:red">this text is red</span> to add text with red color.

Embed Contents

Some websites provide iframe-based embed code which you can also paste into Typora. For example:

1
<iframe height='265' scrolling='no' title='Fancy Animated SVG Menu' src='http://codepen.io/jeangontijo/embed/OxVywj/?height=265&theme-id=0&default-tab=css,result&embed-version=2' frameborder='no' allowtransparency='true' allowfullscreen='true' style='width: 100%;'></iframe>

Video

You can use the <video> HTML tag to embed videos. For example:

1
<video src="xxx.mp4" />

Other HTML Support

You can find more details here.

markdown语法示例

[toc]

块元素

列表

无序列表

  • 这是无序列表
    • 嵌套列表
      • 嵌套列表
        • 还是嵌套列表

有序列表

  1. 这是有序列表
    1. 嵌套有序列表
      1. 又是嵌套

任务列表

  • 任务一
  • 任务二
  • 任务三

代码块

1
2
3
4
5
public class hello {
public static void main(String [] args) {
System.out.println("helloworld");
}
}

表格

字段1 字段2 字段3
1 2 3
4 5 6
7 8 9

引用

这是引用

这是引用

还是引用

脚注

这是一段文字,文字中添加了[^脚注1].

这是水平线


行内元素

链接

外部链接

行内链接

这是行内链接的例子1

这是http://www.baidu.com的例子2

参考链接

这是参考链接的例子

内部链接

这是[内部链接](# 块元素)的例子

插入图片

这是一个图片。使用链接插入。

再来一个图片

行内代码

java的输出打印是 System.out.println("hello markdown").

字体样式

强调

强调1

强调2

加粗

加粗了

加粗了又

删除线

删除了,不要了

高亮显示

==高亮显示哦==

小图标(Emoji )

这个是开心的小图标:happy:

这是愤怒的小图标::angry:

HTML

待完善

参考链接

脚注

[^脚注1]: 这是脚注1 的内容

chrome快捷键汇总

# chrome快捷键汇总

Keyboard shortcuts for opening DevTools

To open DevTools, press the following keyboard shortcuts while your cursor is focused on the browser viewport:

Action Mac Windows / Linux
Open whatever panel you used last Command+Option+I F12 or Ctrl+Shift+I
Open the Console panel Command+Option+J Ctrl+Shift+J
Open the Elements panel Command+Shift+C or Command+Option+C Ctrl+Shift+C

#Global keyboard shortcuts

The following keyboard shortcuts are available in most, if not all, DevTools panels.

Action Mac Windows / Linux
Show Settings ? or Function+F1 ? or F1
Focus the next panel Command+] Ctrl+]
Focus the previous panel Command+[ Ctrl+[
Switch back to whatever docking position you last used. If DevTools has been in its default position for the entire session, then this shortcut undocks DevTools into a separate window Command+Shift+D Ctrl+Shift+D
Toggle Device Mode Command+Shift+M Ctrl+Shift+M
Toggle Inspect Element Mode Command+Shift+C Ctrl+Shift+C
Open the Command Menu Command+Shift+P Ctrl+Shift+P
Toggle the Drawer Escape Escape
Normal reload Command+R F5 or Ctrl+R
Hard reload Command+Shift+R Ctrl+F5 or Ctrl+Shift+R
Search for text within the current panel. Not supported in the Audits, Application, and Security panels Command+F Ctrl+F
Opens the Search tab in the Drawer, which lets you search for text across all loaded resources Command+Option+F Ctrl+Shift+F
Open a file in the Sources panel Command+O or Command+P Ctrl+O or Ctrl+P
Zoom in Command+Shift++ Ctrl+Shift++
Zoom out Command+- Ctrl+-
Restore default zoom level Command+0 Ctrl+0
Run snippet Press Command+O to open the Command Menu, type ! followed by the name of the script, then press Enter Press Ctrl+O to open the Command Menu, type ! followed by the name of the script, then press Enter

#Elements panel keyboard shortcuts

Action Mac Windows / Linux
Undo change Command+Z Ctrl+Z
Redo change Command+Shift+Z Ctrl+Y
Select the element above / below the currently-selected element Up Arrow / Down Arrow Up Arrow / Down Arrow
Expand the currently-selected node. If the node is already expanded, this shortcut selects the element below it Right Arrow Right Arrow
Collapse the currently-selected node. If the node is already collapsed, this shortcut selects the element above it Left Arrow Left Arrow
Expand or collapse the currently-selected node and all of its children Hold Option then click the arrow icon next to the element’s name Hold Ctrl+Alt then click the arrow icon next to the element’s name
Toggle Edit Attributes mode on the currently-selected element Enter Enter
Select the next / previous attribute after entering Edit Attributes mode Tab / Shift+Tab Tab / Shift+Tab
Hide the currently-selected element H H
Toggle Edit as HTML mode on the currently-selected element Function+F2 F2

#Styles pane keyboard shortcuts

Action Mac Windows / Linux
Go to the line where a property value is declared Hold Command then click the property value Hold Ctrl then click the property value
Cycle through the RBGA, HSLA, and Hex representations of a color value Hold Shift then click the Color Preview box next to the value Hold Shift then click the Color Preview box next to the value
Select the next / previous property or value Click a property name or value then press Tab / Shift+Tab Click a property name or value then press Tab / Shift+Tab
Increment / decrement a property value by 0.1 Click a value then press Option+Up Arrow / Option+Down Arrow Click a value then press Alt+Up Arrow / Alt+Down Arrow
Increment / decrement a property value by 1 Click a value then press Up Arrow / Down Arrow Click a value then press Up Arrow / Down Arrow
Increment / decrement a property value by 10 Click a value then press Shift+Up Arrow / Shift+Down Arrow Click a value then press Shift+Up Arrow / Shift+Down Arrow
Increment / decrement a property value by 100 Click a value then press Command+Up Arrow / Command+Down Arrow Click a value then press Ctrl+Up Arrow / Ctrl+Down Arrow
Cycle through the degrees (deg), gradians (grad), radians (rad) and turns (turn) representations of an angle value Hold Shift then click the Angle Preview box next to the value Hold Shift then click the Angle Preview box next to the value
Increment / decrement an angle value by 1 Click the Angle Preview box next to the value then press Up Arrow / Down Arrow Click the Angle Preview box next to the value then press Up Arrow / Down Arrow
Increment / decrement an angle value by 10 Click the Angle Preview box next to the value then press Shift+Up Arrow / Shift+Down Arrow Click the Angle Preview box next to the value then press Shift+Up Arrow / Shift+Down Arrow
Increment / decrement an angle value by 15 Click the Angle Preview box next to the value then press Shift, click / mouse slide on the Angle Clock Overlay Click the Angle Preview box next to the value then press Shift, click / mouse slide on the Angle Clock Overlay

#Sources panel keyboard shortcuts

Action Mac Windows / Linux
Pause script execution (if currently running) or resume (if currently paused) F8 or Command+\ F8 or Ctrl+\
Step over next function call F10 or Command+’ F10 or Ctrl+’
Step into next function call F11 or Command+; F11 or Ctrl+;
Step out of current function Shift+F11 or Command+Shift+; Shift+F11 or Ctrl+Shift+;
Continue to a certain line of code while paused Hold Command and then click the line of code Hold Ctrl and then click the line of code
Select the call frame below / above the currently-selected frame Ctrl+. / Ctrl+, Ctrl+. / Ctrl+,
Save changes to local modifications Command+S Ctrl+S
Save all changes Command+Option+S Ctrl+Alt+S
Go to line Ctrl+G Ctrl+G
Jump to a line number of the currently-open file Press Command+O to open the Command Menu, type : followed by the line number, then press Enter Press Ctrl+O to open the Command Menu, type : followed the line number, then press Enter
Jump to a column of the currently-open file (for example line 5, column 9) Press Command+O to open the Command Menu, type :, then the line number, then another :, then the column number, then press Enter Press Ctrl+O to open the Command Menu, type :, then the line number, then another :, then the column number, then press Enter
Go to a function declaration (if currently-open file is HTML or a script), or a rule set (if currently-open file is a stylesheet) Press Command+Shift+O, then type in the name of the declaration / rule set, or select it from the list of options Press Ctrl+Shift+O, then type in the name of the declaration / rule set, or select it from the list of options
Close the active tab Option+W Alt+W

#Code Editor keyboard shortcuts

Action Mac Windows / Linux
Delete all characters in the last word, up to the cursor Option+Delete Ctrl+Delete
Add or remove a line-of-code breakpoint Focus your cursor on the line and then press Command+B Focus your cursor on the line and then press Ctrl+B
Go to matching bracket Ctrl+M Ctrl+M
Toggle single-line comment. If multiple lines are selected, DevTools adds a comment to the start of each line Command+/ Ctrl+/
Select / de-select the next occurrence of whatever word the cursor is on. Each occurrence is highlighted simultaneously Command+D / Command+U Ctrl+D / Ctrl+U

#Performance panel keyboard shortcuts

Action Mac Windows / Linux
Start / stop recording Command+E Ctrl+E
Save recording Command+S Ctrl+S
Load recording Command+O Ctrl+O

#Memory panel keyboard shortcuts

Action Mac Windows / Linux
Start / stop recording Command+E Ctrl+E

#Console panel keyboard shortcuts

Action Mac Windows / Linux
Accept autocomplete suggestion Right Arrow or Tab Right Arrow or Tab
Reject autocomplete suggestion Escape Escape
Get previous statement Up Arrow Up Arrow
Get next statement Down Arrow Down Arrow
Focus the Console Ctrl+` Ctrl+`
Clear the Console Command+K or Option+L Ctrl+L
Force a multi-line entry. Note that DevTools should detect multi-line scenarios by default, so this shortcut is now usually unnecessary Command+Return Shift+Enter
Execute Return Enter
Expand all sub-properties of an object that’s been logged to the Console Hold Alt then click Expandimg Hold Alt then click Expand

版本选型

选型

版本种类

1
2
3
4
5
6
7
8
#眼花缭乱
snapshot 快照 alpha 内测 beta 公测 release 稳定版本 GA(general availability) 最稳定版本
Final 正式版 Pro(professional) 专业版 Plus 加强版
Retail 零售版 DEMO 演示版 Build 内部标号 Delux 豪华版 (deluxe:豪华的,华丽的)
Corporation或Enterpraise 企业版
M1 M2 M3 M是milestone的简写 里程碑的意思
RC 版本RC:(Release Candidate),几乎就不会加入新的功能了,而主要着重于除错
SR(Service Release) 修正版 Trial 试用版 Shareware 共享版 Full 完全版

常用版本

1
2
3
4
5
6
7
8
9
10
11
#常用
build-snapshot:开发版本,也叫快照版本。当前版本处于开发中,开发完成之后自己测试和让别人测试
(通常Build后面的数字越大,软件版本越新,例如:Windows 优化大师 v5.4 Build 602)

M1...M2(Milestone):里程碑版本,在版发布之前 会出几个里程碑的版本。使用snapshot版本开发了一个时间,觉得最近写代码杠杠的,那么就整几个里程碑版本记录下吧,记录我们这个重大的时刻,是你我未来的回忆。

RC1…RC2(Release Candidates):发布候选。内部开发到一定阶段了,各个模块集成后,经过细心的测试整个开发团队觉得软件已经稳定没有问题了,可以对外发行了。

release:正式版本。发布候选差不多之后,那么说明整个框架到了一定的阶段了,可投入市场大面积使用了,那么发布出去,让广大用户来吃吃香吧。

SR1…SR2(Service Release):修正版。这是啥意思呐,这不release版本发布之后,让广大群体使用了嘛,再牛逼的架构师,也无法写出零bug的代码,那么这时候,就优先对于release版本的问题进行修复,这时候每次迭代的版本就是SR1,SR2,SR3。

版本迭代

1
2
3
4
5
6
7
8
9
10
#开发流程的版本迭代
snapshot –> M1…MX –> RC1…RCX –> release –> SR1…SRX

对应的文字理解:
(1)开发版本(BS) --(开发到一个小阶段,就要标记下)--> 里程碑版本(MX)
(2)里程碑版本(MX) --(版本到了一个相对稳定的阶段可以对外发行但还存在修复的问题,此时只做修复,不做新功能的增加)--> 发布候选(RC1)
(3)发布候选(RC1)--(BUG修复完成,发布)-->正式版本(release)
(4)正式版本(release) --(外界反馈存在一些问题,进行内部在修复)--> 修正版本(SRX)

#结论:版本格式-> 主版本号.子版本号.修正版本号.软件版本阶段

网站英文版本标识

  • CURRENt: 当前推荐的版本
  • GA: 稳定版,可用于生产
  • PRE: 预览版本/里程碑版(M1,M2….milestone)
  • SNAPSHOT: 快照(打死不选)

选择

  1. 打死不用 非稳定版本/ end-of-life(不维护)版本
  2. release版本先等等(刚发布等别人去探雷);
  3. 推荐 SR2以后的可以放心使用;

activiti-6.0解读

activiti-6.0.0

基本概念

  • 工作流(Workflow),就是“业务过程的部分或整体在计算机应用环境下的自动化”,它主要解决的是“使在多个参与者之间按照某种预定义的规则传递文档、信息或任务的过程自动进行,从而实现某个预期的业务目标,或者促使此目标的实现”。

  • BPMN2.0

  • 并行网关(parallelGateWay)

    并行网关的功能是基于进入和外出的顺序流的:

    分支(fork):并行后的所有外出顺序流,为每个顺序流都创建一个并发分支。

    汇聚(join):所有到达并行网关,在此等待的进入分支,直到所有进入顺序流的分支都到达以后,流程就会通过汇聚网关。

    并行网关不会解析条件。即使顺序流中定义了条件,也会被忽略。

    并行网关不需要是“平衡的”(比如, 对应并行网关的进入和外出节点数目不一定相等)。如图中标示是合法的:

activiti

activiti核心API

名称 说明
ProcessEngine 流程引擎,可以获得其他所有的Service。
RepositoryService Repository中存储了流程定义文件、部署和支持数据等信息;RepositoryService提供了对repository的存取服务。
RuntimeService 提供启动流程、查询流程实例、设置获取流程实例变量等功能。
TaskService 提供运行时任务查询、领取、完成、删除以及变量设置等功能。
HistoryService 用于获取正在运行或已经完成的流程实例的信息。
FormService 提供定制任务表单和存储表单数据的功能,注意存储表单数据可选的功能,也可以向自建数据表中提交数据。
IdentityService 提供对内建账户体系的管理功能,注意它是可选的服务,可以是用外部账户体系。
ManagementService 较少使用,与流程管理无关,主要用于Activiti系统的日常维护。

完成一次流程的处理,常见步骤以及他们使用的Service如下图所示:

ProcessInstance 和 Execution 的区别

流程实例就表示一个流程从开始到结束的最大的流程分支,即一个流程中流程实例只有一个。

Activiti用 Execution 去描述流程执行的每一个节点。在没有并发的情况下,Execution就是同ProcessInstance。流程按照流程定义的规则执行一次的过程,就可以表示执行对象Execution。

从源代码中可以看出ProcessInstance就是Execution。但在现实意义上有所区别:

在单线流程中,如上图的贷款流程,ProcessInstance与Execution是一致的。

这个例子有一个特点:wire money(汇钱)和archive(存档)是并发执行的。这个时候,总线路代表ProcessInstance,而分线路中每个活动代表Execution。

(1)如果是单例流程,执行对象ID就是流程实例ID

(2)如果一个流程有分支和聚合,那么执行对象ID和流程实例ID就不相同

(3)一个流程中,流程实例只有1个,执行对象可以存在多个。

流程变量

在流程执行或者任务执行的过程中,用于设置和获取变量,使用流程变量在流程传递的过程中传递业务参数。

对应 act_ru_variable 和 act_hi_varinst 表。

Currently conditionalExpressions can only be used with UEL, detailed info about these can be found in section Expressions. The expression used should resolve to a boolean value, otherwise an exception is thrown while evaluating the condition.

数据库相关

1
2
3
4
5
6
7
8
Activiti 工作流总共包含 23 张数据表(现在是25张,新增了 ACT_EVT_LOG 和 ACT_PROCDEF_INFO )

Activiti的后台是有数据库的支持,所有的表都以ACT_开头。 第二部分是表示表的用途的两个字母标识。 用途也和服务的API对应。
ACT_RE_*: 'RE'表示repository。 这个前缀的表包含了流程定义和流程静态资源 (图片,规则,等等)。对应RepositoryService接口
ACT_RU_*: 'RU'表示runtime。 这些运行时的表,包含流程实例,任务,变量,异步任务,等运行中的数据。 Activiti只在流程实例执行过程中保存这些数据, 在流程结束时就会删除这些记录。 这样运行时表可以一直很小速度很快。对应RuntimeService接口和TaskService接口
ACT_ID_*: 'ID'表示identity。 这些表包含身份信息,比如用户,组等等。对应IdentityService接口
ACT_HI_*: 'HI'表示history。 这些表包含历史数据,比如历史流程实例, 变量,任务等等。对应HistoryService接口
ACT_GE_*: 'GE'表示general。通用数据, 用于不同场景下,如存放资源文件。
表分类 表名 解释
一般数据 ACT_GE_BYTEARRAY 通用的流程定义和流程资源
ACT_GE_PROPERTY 系统相关属性
流程定义表 ACT_RE_MODEL 模型信息
ACT_RE_PROCDEF 已部署的流程定义
ACT_RE_DEPLOYMENT 部署单元信息(和ACT_RE_PROCDEF配合使用)
运行实例表 ACT_RU_EXECUTION 运行时流程执行实例
ACT_RU_IDENTITYLINK 运行时用户关系信息
ACT_RU_TASK 运行时任务
ACT_RU_VARIABLE 运行时变量表
ACT_RU_JOB 运行时作业
ACT_RU_EVENT_SUBSCR 运行时事件
流程历史记录 ACT_HI_ACTINST 历史的流程实例
ACT_HI_ATTACHMENT 历史的流程附件
ACT_HI_COMMENT 历史的说明性信息
ACT_HI_IDENTITYLINK 历史的流程运行过程中用户关系
ACT_HI_DETAIL 历史的流程运行中的细节信息
ACT_HI_PROCINST 历史的流程实例
ACT_HI_TASKINST 历史的任务实例
ACT_HI_VARINST 历史的流程运行中的变量信息
用户用户组表 ACT_ID_GROUP 身份信息-组信息
ACT_ID_USER 身份信息-用户信息
ACT_ID_MEMBERSHIP 身份信息-用户和组关系的中间表
ACT_ID_INFO 身份信息-XXX
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
select * from act_ge_bytearray; -- -通用的流程定义和流程资源(一般数据)
select * from act_ge_property; -- -系统相关属性(一般数据)

select * from act_hi_actinst; -- -历史的流程实例(流程历史记录)
select * from act_hi_attachment; -- -历史的流程附件(流程历史记录)
select * from act_hi_comment; -- -历史的说明性信息(流程历史记录)
select * from act_hi_detail; -- -历史的流程运行中的细节信息(流程历史记录)
select * from act_hi_identitylink; -- -历史的流程运行过程中用户关系,包括提交人,候选人,参与者(流程历史记录)
select * from act_hi_procinst; -- -历史的流程实例(流程历史记录)
select * from act_hi_taskinst; -- -历史的任务实例(流程历史记录)
select * from act_hi_varinst; -- -历史的流程运行中的变量信息(流程历史记录)

select * from act_id_group; -- -身份信息-组信息(用户用户组表)
select * from act_id_info; -- -身份信息-组信息(用户用户组表)
select * from act_id_membership; -- -身份信息-用户和组关系的中间表(用户用户组表)
select * from act_id_user; -- -身份信息-用户信息(用户用户组表)

select * from act_re_deployment; -- -部署单元信息(流程定义表)
select * from act_re_model; -- -模型信息(流程定义表)
select * from ACT_DE_MODEL; -- -模型信息(流程定义表-sunway)
select * from act_re_procdef; -- -已部署的流程定义(流程定义表)
select * from act_ru_event_subscr; -- -运行时事件(运行实例表)
select * from act_ru_execution; -- -运行时流程执行实例(运行实例表)
select * from act_ru_identitylink; -- -运行时用户关系信息,包括提交人,候选人,参与者(运行实例表)
select * from act_ru_job; -- -运行时作业(运行实例表)
select * from act_ru_task; -- -运行时任务(运行实例表)
select * from act_ru_variable; -- -运行时变量表(运行实例表)

act_ru_identitylink和act_hi_identitylink

对应api:

1
2
taskService.addCandidateUser(taskId,userId)
taskService.addCandidateGroup(taskId,groupId)
  1. ID_: _
  2. REV_:版本号
  3. GROUP_ID_: 对应 act_id_group 中的ID_
  4. TYPE_:类型
  5. USER_ID_:对应 act_id_user 中的ID_
  6. TASK_ID_:对应 act_ru_task 中的ID_
  7. PROC_INST_ID_: 流程实例ID _
  8. PROC_DEF_ID_:部署流程版本号

注意:

  • ACT_HI_IDENTITYLINK,所有的历史以及当前指派数据都存在这个表中。
  • ACT_RU_IDENTITYLINK,流程结束以后,此流程对应的指派数据将清空。
  • ACT_RU_IDENTITYLINK,多了两个字段 REV_:版本号,PROC_DEF_ID_:部署流程版本号,因为在运行过程中,任务需要知道发起是使用的是那一个流程版本。
  • ACT_RU_IDENTITYLINK,运行中的任务,TASK_ID_字段不为空,PROC_INST_ID_ 为空。
  • ACT_RU_IDENTITYLINK,结束的任务,TASK_ID_ 字段为空,PROC_INST_ID_ 不为空。

最后,再来看看比较重要的TYPE_字段:

  • starterUSER_IDPROC_INST_ID_,记录流程的发起者
  • candidateUSER_ID_GROUP_ID_ 其中一个必须有值、TASK_ID_有值,记录当前任务的指派人或指派组。指派人:类型为 participant,USER_ID_ 有值;指派组:类型为candidate,GROUP_ID_有值;
  • participantUSER_IDPROC_INST_ID_有值,记录流程任务的参与者。

流程节点抽象

画流程图

命名规范

技巧

获取当前活动任务节点

1
2
3
4
//根据流程实例 ID 获取当前活动任务
Task task = taskService.createTaskQuery().processInstanceId("流程实例ID").active().singleResult();
String taskId = task.getId();
System.out.println("任务ID"+taskId);

整合项目用户角色和工作流用户角色

1
2
3
4
5
6
7
8
9
10
11
12
13
//项目中每创建一个新用户,对应的要创建一个Activiti用户
//两者的userId和userName一致
User admin=identityService.newUser("1");
admin.setLastName("admin");
identityService.saveUser(admin);

//项目中每创建一个角色,对应的要创建一个Activiti用户组
Group adminGroup=identityService.newGroup("1");
adminGroup.setName("admin");
identityService.saveGroup(adminGroup);

//用户与用户组关系绑定
identityService.createMembership("1","1");

部署流程定义+启动流程实例

查看指派人的任务节点

指派人分配方式

  1. 在taskProcess.bpmn中直接写 assignee=“张三丰”
  2. 在taskProcess.bpmn中写 assignee=“#{userID}”,变量的值要是String的。使用流程变量指定办理人
  3. 使用TaskListener接口,要使类实现该接口,在类中定
    delegateTask.setAssignee(assignee);// 指定个人任务的办理人
  4. 使用任务ID和办理人重新指定办理人:

processEngine.getTaskService().setAssignee(taskId, userId);

指派组分配方式

组任务及三种分配方式:

  1. 在taskProcess.bpmn中直接写 candidate-users=“小A,小B,小C,小D”

  2. 在taskProcess.bpmn中写 candidate-users =“#{userIDs}”,变量的值要是String的。

    使用流程变量指定办理人

Map<String, Object> variables = new HashMap<String, Object>();

variables.put(“userIDs”, “大大,小小,中中”);

  1. 使用TaskListener接口,使用类实现该接口,在类中定义:
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
//添加组任务的用户
delegateTask.addCandidateUser(userId1);
delegateTask.addCandidateUser(userId2);
//组任务分配给个人任务(认领任务)
processEngine.getTaskService().claim(taskId, userId);
//个人任务分配给组任务
processEngine.getTaskService(). setAssignee(taskId, null);
//向组任务添加人员
processEngine.getTaskService().addCandidateUser(taskId, userId);
//向组任务删除人员
processEngine.getTaskService().deleteCandidateUser(taskId, userId);

// TaskServiceImpl 源码参考

public void setAssignee(String taskId, String userId) {
commandExecutor.execute(new AddIdentityLinkCmd(taskId, userId, AddIdentityLinkCmd.IDENTITY_USER, IdentityLinkType.ASSIGNEE));
}

public void setOwner(String taskId, String userId) {
commandExecutor.execute(new AddIdentityLinkCmd(taskId, userId, AddIdentityLinkCmd.IDENTITY_USER, IdentityLinkType.OWNER));
}

public void addCandidateUser(String taskId, String userId) {
commandExecutor.execute(new AddIdentityLinkCmd(taskId, userId, AddIdentityLinkCmd.IDENTITY_USER, IdentityLinkType.CANDIDATE));
}

public void addCandidateGroup(String taskId, String groupId) {
commandExecutor.execute(new AddIdentityLinkCmd(taskId, groupId, AddIdentityLinkCmd.IDENTITY_GROUP, IdentityLinkType.CANDIDATE));
}

public void addUserIdentityLink(String taskId, String userId, String identityLinkType) {
commandExecutor.execute(new AddIdentityLinkCmd(taskId, userId, AddIdentityLinkCmd.IDENTITY_USER, identityLinkType));
}

public void addGroupIdentityLink(String taskId, String groupId, String identityLinkType) {
commandExecutor.execute(new AddIdentityLinkCmd(taskId, groupId, AddIdentityLinkCmd.IDENTITY_GROUP, identityLinkType));
}

public void deleteCandidateGroup(String taskId, String groupId) {
commandExecutor.execute(new DeleteIdentityLinkCmd(taskId, null, groupId, IdentityLinkType.CANDIDATE));
}

public void deleteCandidateUser(String taskId, String userId) {
commandExecutor.execute(new DeleteIdentityLinkCmd(taskId, userId, null, IdentityLinkType.CANDIDATE));
}

public void deleteGroupIdentityLink(String taskId, String groupId, String identityLinkType) {
commandExecutor.execute(new DeleteIdentityLinkCmd(taskId, null, groupId, identityLinkType));
}

public void deleteUserIdentityLink(String taskId, String userId, String identityLinkType) {
commandExecutor.execute(new DeleteIdentityLinkCmd(taskId, userId, null, identityLinkType));
}

public List<IdentityLink> getIdentityLinksForTask(String taskId) {
return commandExecutor.execute(new GetIdentityLinksForTaskCmd(taskId));
}

// DelegateTask 源码参考
/** Adds the given user as a candidate user to this task. */
void addCandidateUser(String userId);

`

查询指派人任务和指派组任务

1
2
3
4
5
6
7
8
9
10
11
12
13
// 查询指派人任务节点
List<Task> list = processEngine.getTaskService()
.createTaskQuery()
.taskAssignee(userId)
.list();
// 查看指派组任务节点
List<Task> list = processEngine.getTaskService()
.createTaskQuery()//
.taskCandidateUser(userId)
.list();
// 查看节点指派组人员列表
List<IdentityLink> list = processEngine.getTaskService()
.getIdentityLinksForTask(taskId);

认领任务与指派人回退到指派组

1
2
3
4
5
// 将指派组的任务指派给个人处理
processEngine.getTaskService().claim(taskId, userId);

// 将指派组的任务指派给个人后,又取消指派,由原来的指派组处理
processEngine.getTaskService().setAssignee(taskId, null);

向指派组中添加额外审核人

1
2
processEngine.getTaskService().addCandidateUser(taskId, userId);
processEngine.getTaskService().deleteCandidateUser(taskId, userId);

改派

流程流转时,某个环节的任务处理人变更(即改派)是一种非常常见的需求,本来任务处理人可能是A,但是A因为有事处理不了,管理员需要将该单子改派给B临时处理下。

其实改派的实现很简单,就是为当前任务重新设置处理人,调用如下方法即可:

1
2
3
4
5
// 方式一
taskService.setAssignee("taskId", "userId");
// 方式二,该方式与上面的主要区别是,claim方法会去检查当前是否已经有处理人,如果有则会抛错,需要先调用 unclaim 方法。
taskService.unclaim("taskId");
taskService.claim("taskId", "userId");

自由跳转

思路

思路一

在运行过程中,动态修改Activiti的流程定义,修改领导审批环节的出线,使之流转到审批信息填写,在流转完成后再恢领导审批原先的出线(即结束环节),该方式虽然也能实现自由跳转,但是存在并发的问题,假设A点击回退,此时流程定义已经被修改,领导审批的出线已经变为审批信息填写,同时B点击提交,却发现流程流转到了审批信息填写…B说简直见了鬼。因此不可取。

思路二

使用执行计划直接指定当前流程实例执行所选环节,由于在并发情况下当前任务的执行id是唯一的,因此该方式也没有带来不安全性,下面基于此实现贴代码:

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
/**
* 继承NeedsActiveTaskCmd主要是为了在跳转时要求当前任务不能是挂起状态,也可以直接实现Command接口
* Created by xujia on 2020/2/10
*/
public class DeleteTaskCmd extends NeedsActiveTaskCmd<String> {

public DeleteTaskCmd(String taskId){
super(taskId);
}

public String execute(CommandContext commandContext, TaskEntity currentTask){
TaskEntityManagerImpl taskEntityManager = (TaskEntityManagerImpl)commandContext.getTaskEntityManager();
// 获取当前任务的执行对象实例
ExecutionEntity executionEntity = currentTask.getExecution();
// 删除当前任务,来源任务
taskEntityManager.deleteTask(currentTask, "jumpReason", false, false);
// 返回当前任务的执行对象id
return executionEntity.getId();
}
public String getSuspendedTaskException() {
return "挂起的任务不能跳转";
}
}

/**
* 执行自由跳转命令
* Created by xujia on 2020/2/10
*/
public class SetFLowNodeAndGoCmd implements Command<Void> {

/**
* 目标节点对象
*/
private FlowNode flowElement;
/**
* 当前任务执行id
*/
private String executionId;

public SetFLowNodeAndGoCmd(FlowNode flowElement,String executionId){
this.flowElement = flowElement;
this.executionId = executionId;
}

public Void execute(CommandContext commandContext){
// 获取目标节点的来源连线
List<SequenceFlow> flows = flowElement.getIncomingFlows();
if(flows==null || flows.size()<1){
throw new ActivitiException("回退错误,目标节点没有来源连线");
}
// 随便选一条目标节点的入线来执行,使当前执行计划为:从所选择的流程线流转到目标节点,实现跳转
ExecutionEntity executionEntity = commandContext.getExecutionEntityManager().findById(executionId);
executionEntity.setCurrentFlowElement(flows.get(0));
commandContext.getAgenda().planTakeOutgoingSequenceFlowsOperation(executionEntity, true);
return null;
}
}

// 调用测试
@Test
public void listTaskTest() {
// 获取当前任务
Task currentTask = taskService.createTaskQuery().taskId("132502").singleResult();
BpmnModel bpmnModel = repositoryService.getBpmnModel(currentTask.getProcessDefinitionId());
// 获取流程定义
Process process = bpmnModel.getMainProcess();
// 获取目标节点定义
FlowNode targetNode = (FlowNode) process.getFlowElement("sid-C24BA4F5-F744-4DD7-8D51-03C3698044D2");

// 删除当前运行任务,同时返回执行id,该id在并发情况下也是唯一的
String executionEntityId = managementService.executeCommand(new DeleteTaskCmd(currentTask.getId()));
// 流程执行到来源节点
managementService.executeCommand(new SetFLowNodeAndGoCmd(targetNode, executionEntityId));
}

下一环节未审批,本环节可撤回

实现思路

  1. 获取当前任务所在的节点 (FlowNode)
  2. 获取所在节点的流出方向 (SequenceFlow1)
  3. 记录所在节点的流出方向,并将所在节点的流出方向清空
  4. 获取目标节点 (要撤回到的节点)
  5. 创建新的方向 (SequenceFlow2)
  6. 用新的流出方向连接当前节点和目标节点(SequenceFlow2)
  7. 完成当前任务
  8. 还原当前节点的流出方向(SequenceFlow1)

参考示例

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
public void revoke(String objId) throws Exception {

Task task = taskService.createTaskQuery().processInstanceBusinessKey(objId).singleResult();
if(task==null) {
throw new ServiceException("流程未启动或已执行完成,无法撤回");
}

LoginUser loginUser = SessionContext.getLoginUser();
List<HistoricTaskInstance> htiList = historyService.createHistoricTaskInstanceQuery()
.processInstanceBusinessKey(objId)
.orderByTaskCreateTime()
.asc()
.list();
String myTaskId = null;
HistoricTaskInstance myTask = null;
for(HistoricTaskInstance hti : htiList) {
if(loginUser.getUsername().equals(hti.getAssignee())) {
myTaskId = hti.getId();
myTask = hti;
break;
}
}
if(null==myTaskId) {
throw new ServiceException("该任务非当前用户提交,无法撤回");
}

String processDefinitionId = myTask.getProcessDefinitionId();
ProcessDefinitionEntity processDefinitionEntity = (ProcessDefinitionEntity) repositoryService.createProcessDefinitionQuery().processDefinitionId(processDefinitionId).singleResult();
BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);

//变量
// Map<String, VariableInstance> variables = runtimeService.getVariableInstances(currentTask.getExecutionId());
String myActivityId = null;
List<HistoricActivityInstance> haiList = historyService.createHistoricActivityInstanceQuery()
.executionId(myTask.getExecutionId()).finished().list();
for(HistoricActivityInstance hai : haiList) {
if(myTaskId.equals(hai.getTaskId())) {
myActivityId = hai.getActivityId();
break;
}
}
FlowNode myFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(myActivityId);


Execution execution = runtimeService.createExecutionQuery().executionId(task.getExecutionId()).singleResult();
String activityId = execution.getActivityId();
logger.warn("------->> activityId:" + activityId);
FlowNode flowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(activityId);

//记录原活动方向
List<SequenceFlow> oriSequenceFlows = new ArrayList<SequenceFlow>();
oriSequenceFlows.addAll(flowNode.getOutgoingFlows());

//清理活动方向
flowNode.getOutgoingFlows().clear();
//建立新方向
List<SequenceFlow> newSequenceFlowList = new ArrayList<SequenceFlow>();
SequenceFlow newSequenceFlow = new SequenceFlow();
newSequenceFlow.setId("newSequenceFlowId");
newSequenceFlow.setSourceFlowElement(flowNode);
newSequenceFlow.setTargetFlowElement(myFlowNode);
newSequenceFlowList.add(newSequenceFlow);
flowNode.setOutgoingFlows(newSequenceFlowList);

Authentication.setAuthenticatedUserId(loginUser.getUsername());
taskService.addComment(task.getId(), task.getProcessInstanceId(), "撤回");

Map<String,Object> currentVariables = new HashMap<String,Object>();
currentVariables.put("applier", loginUser.getUsername());
//完成任务
taskService.complete(task.getId(),currentVariables);
//恢复原方向
flowNode.setOutgoingFlows(oriSequenceFlows);
}

数据库设计

建议数据库冗余设计:在业务表设计的时候添加一列:PROCESS_INSTANCE_ID varchar2(64),在流程启动之后把

流程ID更新到业务表中,这样不管从业务还是流程都可以查询到对方!
特别说明: 此方法启动时自动选择最新版本的流程定义

数据库:ACT_RE_PROCDEF;每次部署一次流程定义就会添加一条数据,同名的版本号累加。
特别说明: 此可以指定不同版本的流程定义,让用户多一层选择

部署示例

  1. 下载
  1. 配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#datasource.driver=org.h2.Driver
#datasource.url=jdbc:h2:mem:activiti;DB_CLOSE_DELAY=-1

# 配置连接MySQL,Activiti Explorer默认运行在H2内存数据库上
datasource.driver=com.mysql.jdbc.Driver
datasource.url=jdbc:mysql://127.0.0.1:3306/activiti6ui?serverTimezone=Asia/Shanghai&characterEncoding=utf8

datasource.username=root
datasource.password=root

#hibernate.dialect=org.hibernate.dialect.H2Dialect
hibernate.dialect=org.hibernate.dialect.MySQLDialect
#hibernate.dialect=org.hibernate.dialect.Oracle10gDialect
#hibernate.dialect=org.hibernate.dialect.SQLServerDialect
#hibernate.dialect=org.hibernate.dialect.DB2Dialect
#hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
  1. 将3个war包拷贝到tomcat的webapps目录下,启动tomat
  2. 登录验证 默认访问地址 默认用户名/密码:admin/test

参考

开发文档

github

Activiti6.0(十)任务处理人变更(改派)、自由跳转(回退)

bpmn2.0规范

bpmn2.0小本本

bpmn2.0pdf

问题

  • Activiti 6.0 MySql db configuration. Error:Could not create connection to database server

We configured the hibernate.dialect=org.hibernate.dialect.MySQLInnoDBDialect

and upgraded the jar to mysql-connector-java-8.0.11.jar

Thanks.

  • Error querying database. Cause: java.sql.SQLSyntaxErrorException: Table ‘activiti6ui.act_ge_property’ doesn’t exist

需要初始化库,并创建好activiti的表结构

hexo-github-搭建个人博客

hexo

基本概念

  • 布局(layout)

Hexo 有三种默认布局:postpagedraft。在创建这三种不同类型的文件时,它们将会被保存到不同的路径;而您自定义的其他布局和 post 相同,都将储存到 source/_posts 文件夹。

布局 路径
post source/_posts
page source
draft source/_draft
  • 模版(Scaffold)

在新建文章时,Hexo 会根据 scaffolds 文件夹内相对应的文件来建立文件,例如:

1
$ hexo new photo "My Gallery"

在执行这行指令时,Hexo 会尝试在 scaffolds 文件夹中寻找 photo.md,并根据其内容建立文章。

  • 草稿(draft)

这种布局在建立时会被保存到 source/_drafts 文件夹,您可通过 publish 命令将草稿移动到 source/_posts 文件夹,该命令的使用方式与 new 十分类似。

  • 资源文件夹

资源(Asset)代表 source 文件夹中除了文章以外的所有文件,例如图片、CSS、JS 文件等。比方说,如果你的Hexo项目中只有少量图片,那最简单的方法就是将它们放在 source/images 文件夹中。然后通过类似于 ![](/images/image.jpg) 的方法访问它们。

对于那些想要更有规律地提供图片和其他资源以及想要将他们的资源分布在各个文章上的人来说,Hexo也提供了更组织化的方式来管理资源。这个稍微有些复杂但是管理资源非常方便的功能可以通过将 config.yml 文件中的 post_asset_folder 选项设为 true 来打开。

当资源文件管理功能打开后,Hexo将会在你每一次通过 hexo new [layout] <title> 命令创建新文章时自动创建一个文件夹。这个资源文件夹将会有与这个文章文件一样的名字。将所有与你的文章有关的资源放在这个关联文件夹中之后,你可以通过相对路径来引用它们,这样你就得到了一个更简单而且方便得多的工作流。

安装

1
npm install hexo-cli -g

使用

命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 在当前目录或指定目录下初始化网站
$ hexo init [folder]
# 创建文章 您可以在命令中指定文章的布局(layout),默认为 post,可以通过修改 _config.yml 中的 default_layout 参数来指定默认布局
$ hexo new [layout] <title>
$ hexo new page --path about/me "About me"

# 如果使用path参数,则路径即分类(推荐)
$ hexo new --path dir1/dir2/file1.txt "第一个测试文件"

# 生成静态文件 f相当于hexo clean
$ hexo g -f -d --debug
# 启动服务器。默认情况下,访问网址为: http://localhost:4000/
$ hexo s -p 5000 --debug
# 部署网站 -g部署之前预先生成静态文件
$ hexo d -g --debug
# 清除缓存文件 (db.json) 和已生成的静态文件 (public)。在某些情况(尤其是更换主题后),如果发现您对站点的更改无论如何也不生效,您可能需要运行该命令。
$ hexo clean
# 列出网站资料
$ hexo list <type>

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
25433@DESKTOP-5C07FVD MINGW64 /f/personal/blog/hexo (master)
$ hexo new --path dir1/dir2/file1 "第一个分类测试文件"
INFO Created: F:\personal\blog\hexo\source\_posts\dir1\dir2\file1.md

25433@DESKTOP-5C07FVD MINGW64 /f/personal/blog/hexo (master)
$ hexo clean
INFO Deleted database.
INFO Deleted public folder.

25433@DESKTOP-5C07FVD MINGW64 /f/personal/blog/hexo (master)
$ hexo g
INFO Start processing
INFO Generated: categories [[ 'dir1', 'dir2' ]] for post [file1.md]
INFO Files loaded in 329 ms

写作

Front-matter

Front-matter 是文件最上方以 --- 分隔的区域,用于指定个别文件的变量,举例来说:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
title: Hello World
date: 2013/7/13 20:46:25
categories:
- Diary
tags:
- PS3
- Games
---
参数 描述 默认值
layout 布局 config.default_layout
title 标题 文章的文件名
date 建立日期 文件建立日期
updated 更新日期 文件更新日期
comments 开启文章的评论功能 true
tags 标签(不适用于分页)
categories 分类(不适用于分页)
permalink 覆盖文章网址
excerpt Page excerpt in plain text. Use this plugin to format the text
disableNunjucks Disable rendering of Nunjucks tag {{ }}/{% %} and tag plugins when enabled
lang Set the language to override auto-detection Inherited from _config.yml

分类和标签

只有文章支持分类和标签,您可以在 Front-matter 中设置。在其他系统中,分类和标签听起来很接近,但是在 Hexo 中两者有着明显的差别:分类具有顺序性和层次性,也就是说 Foo, Bar 不等于 Bar, Foo;而标签没有顺序和层次。具体参考上边。

1
2
3
4
5
6
7
8
9
10
11
# 会使分类Life成为Diary的子分类,而不是并列分类。因此,有必要为您的文章选择尽可能准确的分类。
categories:
- Diary
- Life

# 如果你需要为文章添加多个分类,可以尝试以下 list 中的方法。
categories:
- [Diary, PlayStation]
- [Diary, Games]
- [Life]
# 此时这篇文章同时包括三个分类: PlayStation 和 Games 分别都是父分类 Diary 的子分类,同时 Life 是一个没有子分类的分类。

一键部署

  1. 安装hexo-deployer-git
1
$ npm install hexo-deployer-git --save
  1. 修改配置
1
2
3
4
5
6
# 不管是git还是gitee,都要创建与登录用户名相同的仓库,保存静态代码,否则容易因路径问题,导致图片或者js无法加载!!!
deploy:
type: git
repo: <repository url> #https://bitbucket.org/JohnSmith/johnsmith.bitbucket.io
branch: [branch]
message: [message]
  1. 生成站点文件并推送至远程库
1
hexo clean && hexo deploy

配置

网站

参数 描述
title 网站标题
subtitle 网站副标题
description 网站描述
keywords 网站的关键词。支持多个关键词。
author 您的名字
language 网站使用的语言。对于简体中文用户来说,使用不同的主题可能需要设置成不同的值,请参考你的主题的文档自行设置,常见的有 zh-Hanszh-CN
timezone 网站时区。Hexo 默认使用您电脑的时区。请参考时区列表 进行设置,如 America/New_York, Japan, 和 UTC 。一般的,对于中国大陆地区可以使用 Asia/Shanghai

网址

参数 描述 默认值
url 网址, 必须以 http://https:// 开头
root 网站根目录 url's pathname
permalink 文章的永久链接 格式 :year/:month/:day/:title/
permalink_defaults 永久链接中各部分的默认值
pretty_urls 改写permalink 的值来美化 URL
pretty_urls.trailing_index 是否在永久链接中保留尾部的 index.html,设置为 false 时去除 true
pretty_urls.trailing_html 是否在永久链接中保留尾部的 .html, 设置为 false 时去除 (对尾部的 index.html无效) true

目录

参数 描述 默认值
source_dir 资源文件夹,这个文件夹用来存放内容。 source
public_dir 公共文件夹,这个文件夹用于存放生成的站点文件。 public
tag_dir 标签文件夹 tags
archive_dir 归档文件夹 archives
category_dir 分类文件夹 categories
code_dir Include code 文件夹,source_dir 下的子目录 downloads/code
i18n_dir 国际化(i18n)文件夹 :lang
skip_render 跳过指定文件的渲染。匹配到的文件将会被不做改动地复制到 public 目录中。您可使用 glob 表达式来匹配路径。

文章

参数 描述 默认值
new_post_name 新文章的文件名称 :title.md
default_layout 预设布局 post
auto_spacing 在中文和英文之间加入空格 false
titlecase 把标题转换为 title case false
external_link 在新标签中打开链接 true
external_link.enable 在新标签中打开链接 true
external_link.field 对整个网站(site)生效或仅对文章(post)生效 site
external_link.exclude 需要排除的域名。主域名和子域名如 www 需分别配置 []
filename_case 把文件名称转换为 (1) 小写或 (2) 大写 0
render_drafts 显示草稿 false
post_asset_folder 启动Asset 文件夹 false
relative_link 把链接改为与根目录的相对位址 false
future 显示未来的文章 true
highlight 代码块的设置, 请参考Highlight.js 进行设置
prismjs 代码块的设置, 请参考PrismJS 进行设置

分类 & 标签

参数 描述 默认值
default_category 默认分类 uncategorized
category_map 分类别名
tag_map 标签别名

日期 / 时间格式

Hexo 使用 Moment.js 来解析和显示时间。

参数 描述 默认值
date_format 日期格式 YYYY-MM-DD
time_format 时间格式 HH:mm:ss
updated_option 当 Front Matter 中没有指定updatedupdated 的取值 mtime

扩展(主题)

参数 描述
theme 当前主题名称。值为 false时禁用主题
theme_config 主题的配置文件。在这里放置的配置会覆盖主题目录下的 _config.yml 中的配置
deploy 部署部分的设置
meta_generator Meta generator 标签。 值为 false 时 Hexo 不会在头部插入该标签

error

  • can`t deploy my hexo bu hexo-deployer-git,please help me #186

but re-install hexo-deployer-git don’t work for me, but npm install hexo-fs work.

  • 页面报Uncaught TypeError: Cannot read property ‘match‘ of null

主题不好使,换个主题就可以了

  • 分类和标签功能无法使用
1
2
3
4
5
# 添加 layout: "categories"。同理,添加 layout: "tags"。
title: 文章分类
date: 2021-12-20 11:00:02
type: "categories"
layout: "categories"
  • 提交到gitee或者github,没有变化,或部分变化

静等几分钟,可能会有奇迹发生。

参考

  • © 2015-2024 DXShelley
  • Powered by Hexo Theme Ayer

请我喝杯咖啡吧~~~

支付宝
微信