简述systemd和unit,以及awk命令函数示例
简述systemd
System的新特性
- 系统引导时实现服务并行启动
- 按需激活进程
- 系统状态快照
- 基于依赖关系定义服务控制逻辑
System 核心概念:unit
unit由其相关配置文件进行标识、识别和配置;文件中主要包含了系统服务、监听的socket、保存的快照以及其它与init相关的信息。
- 这些配置文件主要保存在:
/usr/lib/systemd/system
/run/systemd/system
/etc/systemd/system
unit的常见类型:
- service unit :文件扩展名为 .service,用于定义系统服务
- Target unit:文件扩展名为 .target,用于模拟实现“运行级别”
- Device unit:文件扩展名 .device,用于定义内核识别的设备
- Mount unit:文件扩展名为 .mount,定义文件系统的挂载点
- Socket unit:文件扩展名 .socket,定义标识进程间通信用到的socket文件
- Snapshot unit: 文件扩展名 .snapshot,管理系统快照
- Swap unit:文件扩展名 .swap,用于标识swap设备
- Automount unit:文件扩展名.automount,文件系统自动挂载点设备
- Path unit;文件扩展名 .path ,用于定义文件系统的文件或目录
关键特性:
- 基于socket的激活机制;socket与程序分离
- 基于bus总线的激活机制
- 基于device设备的激活机制
- 基于path的激活机制
- 系统快照:保存个unit的当前状态信息于持久存储设备中
- 向后兼容sysV init脚本;/etc/init.d/
不兼容:
- Systemctl的命令是固定不变的
- 非由systemd启动的服务,systemctl无法与之通信
管理系统服务:
CentOS 7: service类型的unit文件;
systemctl命令:
control the systemd system and service manger
语法:systemctl [OPTIONS...] COMMAND [NAME...]
- 启动:systemctl start NAME.service
- 停止:systemctl stop NAME.service
- 重启:systemctl restart NAME.service
- 状态:systemctl status NAME.service
- 条件式重启:systemctl try-restart NAME.service
- 重载或重启服务:systemctl reload-or-restart NAME.service
- 重载或条件式重启:systemctl reload-or-try-restart NAME.service
- 查看某服务当前激活与否的状态:systemctl is-active NAME.service
- 查看所有已激活的服务:systemctl list-units –type service
- 查看所有服务(已激活及未激活)systemctl list-units -t service –all
- 设置服务开机自启:systemctl enable NAME.service
- 禁止服务开机自启:systemctl disable NAME.service
- 查看某服务是否设定为开机自启:systemtl is-enabled NAME.service
- 禁止某服务设定为开机自启:systemctl mask NAME.service
- 取消此禁止:systemctl unmask NAME.service
- 查看服务的依赖关系:systemctl list-dependencies NAME.service
管理 target units
-
运行级别:
- 0 ==> runlevel0.target, poweroff.target
- 1 ==> runlevel1.target, rescue.target
- 2 ==> runlevel2.tartet, multi-user.target
- 3 ==> runlevel3.tartet, multi-user.target
- 4 ==> runlevel4.tartet, multi-user.target
- 5 ==> runlevel5.target, graphical.target
- 6 ==> runlevel6.target, reboot.target
-
级别切换:systemctl isolate NAME.target
-
查看级别:systemctl list-units –type target
-
查看所有级别:systemctl list-units –type target -a
-
获取默认运行级别:systemctl get-default
-
修改默认运行级别:systemctl set-default NAME.target
-
切换至紧急救援模式:systemctl rescue
-
切换至emergency模式:systemctl emergency
其它常用命令:
-
关机:systemctl halt;systemctl poweroff
-
重启:systemctl reboot
-
挂起:systemctl suspend
-
快照:systemctl hibernate
-
快照并挂起:systemctl hybrid-sleep
service unit file
-
文件通常由三部分组成:
- [Unit]:定义与unit类型无关的通用选项;用于提供unit的描述信息、unit行为及依赖关系
- [Service]:与特定类型相关的专用选项;此处为service类型
- [Install]:定义由“systemctl enable”以及“systemctl disable”命令在实现服务;启用或禁用时用到的一些选项
-
Unit段的常用选项:
- Description :描述信息;意义性描述
- After :定义unit的启动次序,表示当前unit应该晚于哪些unit启动;其功能与Before相反
- Requies :依赖到其它unit,强依赖;被依赖的unit无法激活时,当前unit即无法激活
- Wants:依赖到其它units,弱依赖;被依赖的unit无法激活时,当前unit可以激活
- Conflicts:定义units间的冲突关系
-
Service 段的常用选项:
-
Type:用于定义影响ExecStart及相关参数的功能的unit进程启动的类型
-
类型:
- simple
- forking
- oneshot
- dbus
- notify
- idle
-
-
EnvironmentFile:环境配置文件
-
ExecStart:指明启动unit要运行命令或脚本
- ExecStartPre:预启动
- ExecStartPost:后启动
-
ExecStop:指明停止unit要运行的命令或脚本
-
Restart:重启unit要运行的命令或脚本
-
-
Install段的常用选项:
- Alias:别名
- RequiredBy:被哪些units所依赖
- WanteBy:被哪些units所依赖
-
**注意:对于新创建的unit文件系统或修改了的unit文件要通知systemd重载此配置文件
systemctl daemon-reload
编译安装如httpd实现通过systemd来管理
#编译apache2.2,htttpd服务的过程如下:
[root@localhost ~]# cd httpd-2.2.32/
[root@localhost ~]# ./configure --prefix=/usr/local/apache2 --sysconfdir=/etc/httpd2
[root@localhost ~]# make
[root@localhost ~]# make install
#安装后配置
[root@localhost ~]# vim /etc/profile.d/httpd2.sh
export PATH=$PATH:/usr/local/apache2/bin
[root@localhost ~]# source /etc/profile.d/httpd2.sh
[root@localhost ~]# vim /etc/ld.so.conf.d/httpd.conf
/usr/local/apache2/lib
[root@localhost ~]# ldconfig -v
[root@localhost ~]# ln -sv /usr/local/apache2/include/ /usr/include/
[root@localhost ~]# vim /etc/man_db.conf
#编辑httpd的unit文件
vim /usr/lib/systemd/system/httpd.service
[Unit]
Description=The httpd service
After=network.target
[Service]
Type=forking
ExecStart=/usr/local/apache2/bin/apachectl start
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/usr/local/apache2/bin/apachectl stop
Restart=/usr/local/apache2/bin/apachectl restart
[Install]
WantedBy=multi-user.target
#编辑完成后通知systemd重载此配置
systemctl daemon-reload
#启动服务
systemctl start httpd.service
#查看服务是否启动
ss -tan 80端口是在监听状态,服务启动成功
#停止服务
systemctl stop httpd.service
#查看状态
systemctl status httpd.service
active (running) 正在运行OK
编译安装如nginx实现通过systemd来管理
./configure --prefix=/usr/local/nginx
#编译后报错error提示需要PCRE库
wget http://mirrors.163.com/centos/7/os/x86_64/Packages/pcre-8.32-17.el7.x86_64.rpm
rpm -ivh pcre-8.32-17.el7.x86_64.rpm
wget http://mirrors.163.com/centos/7/os/x86_64/Packages/pcre-devel-8.32-17.el7.x86_64.rpm
rpm -ivh pcre-devel-8.32-17.el7.x86_64.rpm
./configure --prefix=/usr/local/nginx
#编译后报错error提示需要zlib库
wget http://mirrors.163.com/centos/7/os/x86_64/Packages/zlib-1.2.7-17.el7.x86_64.rpm
rpm -ivh zlib-1.2.7-17.el7.x86_64.rpm
#依赖的库pcre和zlib安装完成后就可以编译安装nginx
./configure --prefix=/usr/local/nginx
make && make install
#安装完成后配置环境变量
vim /etc/profile.d/nginx.sh
export PATH=$PATH:/usr/local/nginx/sbin
#安装完成后添加unit文件
vim /usr/lib/systemd/system/nginx.service
[Unit]
Description=this is nginx service
After=network.target
[Service]
Type=forking
ExecStart=/usr/local/nginx/sbin/nginx
ExecStop=/usr/local/nginx/sbin/nginx -s stop
Restart=/usr/local/nginx/sbin/nginx -s reload
[Install]
WanteBy=multi-user.target
#安装完成后启动
systemctl start nginx.service
ss -tan
#观察到80端口LISTEN,启动成功;外部浏览器访问如图
nginx.png
GUN awk命令
文本处理三剑客:
- grep、egrep、fgrep:文本过滤工具
- sed:行编辑器
- awk:报表、报告生成器,格式化文本输出
GNU awk简称为gawk,我们通常统称为awk
基本用法:gawk [options] 'program' FILE...
- program:
PATTERN{ACTION STATEMENTS}
选项:
-F:指明输入时用到的字段分隔符
-v var=value:自定义变量
示例:
[root@localhost ~]# tail -5 /etc/fstab
#
/dev/mapper/centos-root / xfs defaults 0 0
UUID=55bb7b0d-eb2d-454e-aaaa-fcbf3b0bedcd /boot xfs defaults 0 0
UUID=224da14b-890b-4f1a-8340-5a3ccc016085 /home xfs defaults 0 0
UUID=0a8f2cdd-14bd-4df1-b23a-078f513ad814 swap swap defaults 0 0
[root@localhost ~]# tail -5 /etc/fstab|awk ' {print $2,$4}'
/ defaults
/boot defaults
/home defaults
swap defaults
输出命令
-
print:
print item1,item2,...
- 要点:<1> 逗号分割符;<2> 输出的各item可以是字符串,也可以是数值、当前变量的字段、变量或awk的表达式;<3> 如果省略item,则默认显示$0,整行
-
变量
2.1 内建变量:
FS input field sepperator,默认为空白字符
OFS:output field seperator,默认为空白字符;
示例:[root@localhost ~]# awk -v FS=':' -v OFS=':' '{print $1,$3,$7}' /etc/passwd
RS:input record seperator,输入时的换行符;
ORS:output record seperator,输出时的换行符;
NF:number of field,字段数量
{print NF}, {print $NF}
NR:number of record, 行数;
示例:[root@localhost ~]# awk '{print NR}' /etc/fstab /etc/issue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#显示两个文件总行数
FNR:各文件分别计数;行数;
FILENAME:当前文件名;
ARGC:命令行参数的个数;
ARGV:数组,保存的是命令行所给定的各参数;
示例:
[root@localhost ~]# awk 'BEGIN{print ARGC}' /etc/fstab /etc/issue
3
[root@localhost ~]# awk 'BEGIN{print ARGV[0]}' /etc/fstab /etc/issue
awk
[root@localhost ~]# awk 'BEGIN{print ARGV[1]}' /etc/fstab /etc/issue
/etc/fstab
[root@localhost ~]# awk 'BEGIN{print ARGV[2]}' /etc/fstab /etc/issue
/etc/issue
2.2 自定义变量
<1> -v var=value:变量名区分大小写
例:[root@localhost ~]# awk -v test='hello word' 'BEGIN{print test}'
hello word
<2> 在program中直接定义
例:[root@localhost ~]# awk 'BEGIN{test="hello word";print test}'
hello word
-
printf命令:
-
格式化输出:
printf FORMAT, item1,item2,...
-
要点:
<1> FORMAT必须给出;
<2> 不会自动换行,需要显式给出换行控制符\n;
<3> FORMAT中需要分别为后面的每一个item指定一个格式化符号 -
格式符:
%c:显示字符ASCII码
%d,%i:显示十进制整数
%e,%E:科学计数法数值显示
%f:显示浮点数
%g,%G:以科学计数法或浮点形式显示数值
%s:显示字符串
%u:无符号整数
%%:显示%自身 -
修饰符:
<1>#.[#]:第一个数字控制显示的宽度,第二个#标识小数点之后的精度
<2>-:左对齐;默认为右对齐
<3>+:显示数值的符号
-
示例:
[root@localhost ~]# awk -F: ' {printf "Username:%s, Uid:%d \n", $1,$3}' /etc/passwd
[root@localhost ~]# awk -F: ' {printf "Username:%-15s,UId:%d\n", $1,$3}' /etc/passwd
-
操作符
- 算数操作符:x+y,x-y,x*y,x/y,x^y,x%y,-x,+x
- 字符串操作符:没有符号的操作符,字符串连接
- 赋值操作符:=,+=,-=,*=,/=,%=,^=,++,–
- 比较操作符:>,>=,<,<=,!=,==
- 模式匹配符:是否匹配;!是否不匹配
- 逻辑操作符:&&,||,!
- 函数调用:function_name();
- 传递参数:function_name(argu1,argu2,…)
- 条件表达式:
selector?if-true-expression:if-false-expression
示例:[root@localhost ~]# awk -F: ' {$3>=100?usertype="Common User":usertype="Sysadmin or Sysuser";printf "%15s,%-s\n",$1,usertype}' /etc/passwd
root,Sysadmin or Sysuser
bin,Sysadmin or Sysuser
daemon,Sysadmin or Sysuser
-
PATTERN
<1>空模式 empty:匹配文件每一行
<2>/regular expression/:仅处理能被此处的模式匹配到的行
<3>relational expression:关系表达式,结果有真有假;结果为真才会被处理;结果为非0值,非空字符串时为真。
<4>line ranges:行范围 /pat1/,/pat2/ - 注意:此处不支持直接给出数字的格式
<5> BEGIN/END模式- BEGIN{}:仅在开始处理文件中的文本之前执行一次;
- END{}:仅在文本处理完成之后执行一次;
示例 1:[root@localhost ~]# awk ' /^UUID/{print $1}' /etc/fstab
UUID=55bb7b0d-eb2d-454e-aaaa-fcbf3b0bedcd
UUID=224da14b-890b-4f1a-8340-5a3ccc016085
UUID=0a8f2cdd-14bd-4df1-b23a-078f513ad814
示例 2: [root@localhost ~]# awk -F: '$3>=1000{print $1,$3}' /etc/passwd
nfsnobody 65534
inspur 1000
示例 3: [root@localhost ~]# awk -F: '$NF=="/bin/bash"{print $1,$NF}' /etc/passwd
root /bin/bash
inspur /bin/bash
[root@localhost ~]# awk -F: '$NF~"/bin/bash$"{print $1,$NF}' /etc/passwd
root /bin/bash
inspur /bin/bash
示例 4:[root@localhost ~]# awk -F: '/^d/,/^a/{print $1,$3}' /etc/passwd
daemon 2
adm 3
dbus 81
polkitd 999
abrt 173
示例 5:[root@localhost ~]# awk -F: 'BEGIN{print " username uid\n=========================="} {print $1,$3}END{print "=========\n end"}' /etc/passwd
username uid
==========================
root 0
bin 1
daemon 2
adm 3
lp 4
=========
end
-
常用的ACTION
<1> Expressions
<2> Control statements
<3> Compound Statements
<4> Input statements
<5> Output statements -
控制语句:
if(condition) {statments}
if(condition) {statments} else {statements}
while(conditon) {statments}
do {statements} while(condition)
for(expr1;expr2;expr3) {statements}
break
continue
delete array[index]
delete array
exit
{ statements }
7.1 if-else:
语法:if(condition) statement [else statement]
使用场景:对awk取得的整行或某个字段做条件判断
示例1:
#如果用户的shell为bash,那么显示此用户
[root@localhost ~]# awk -F: '{if($NF=="/bin/bash") print $1}' /etc/passwd
root
inspur
示例2 #如某一行的字段大于5个,则显示,否则不显示
[root@localhost ~]# awk ' {if(NF>=5)print $0}' /etc/fstab
# Created by anaconda on Sun Jul 1 06:20:58 2018
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
/dev/mapper/centos-root / xfs defaults 0 0
UUID=55bb7b0d-eb2d-454e-aaaa-fcbf3b0bedcd /boot xfs defaults 0 0
UUID=224da14b-890b-4f1a-8340-5a3ccc016085 /home xfs defaults 0 0
UUID=0a8f2cdd-14bd-4df1-b23a-078f513ad814 swap swap defaults 0 0
示例3:#使用空间比例大于10%,则显示
[root@localhost ~]# df -h | awk -F[%] '{print $1}'| awk ' {if($NF>10)print $1}'
文件系统
/dev/mapper/centos-root
/dev/sda1
7.2 while循环
语法:while(condition) statement
条件为真进入循环;条件为假退出循环
使用场景:对一行内的多个字段逐一类似处理时使用,对数组中的个元素逐一处理时使用;对每一行的个各字段格式化处理
示例:# /etc/grub2.cfg文件中linux16开头的行统计每一行字段的字符个数,并把大于7个字段的显示出来
[root@localhost ~]# awk '/^[[:space:]]*linux16/{i=1;while(i<=NF){if(length($i)>=7){print $i,length($i)};i++}}' /etc/grub2.cfg
linux16 7
/vmlinuz-3.10.0-693.el7.x86_64 30
root=/dev/mapper/centos-root 28
crashkernel=auto 16
rd.lvm.lv=centos/root 21
LANG=zh_CN.UTF-8 16
linux16 7
/vmlinuz-0-rescue-8e4ba67d04f640d3a12dad38e3d4093b 50
root=/dev/mapper/centos-root 28
crashkernel=auto 16
rd.lvm.lv=centos/root 21
7.3 do-while循环
语法:do statement while(condition)
意义在于至少执行一次
7.4 for循环
语法:for(expr1;expr2;expr) statement
for(variable assignment; condition; iteration process){for-body}
示例:# /etc/grub2.cfg文件中linux16开头的行统计每一行字段的字符个数,并把大于7个字段的显示出来
[root@localhost ~]# awk '/^[[:space:]]*linux16/{for(i=1;i<=NF;i++){if(length($i)>=7){print $i,length($i)}}}' /etc/grub2.cfg
linux16 7
/vmlinuz-3.10.0-693.el7.x86_64 30
root=/dev/mapper/centos-root 28
crashkernel=auto 16
rd.lvm.lv=centos/root 21
LANG=zh_CN.UTF-8 16
linux16 7
/vmlinuz-0-rescue-8e4ba67d04f640d3a12dad38e3d4093b 50
root=/dev/mapper/centos-root 28
crashkernel=auto 16
rd.lvm.lv=centos/root 21
7.5 switch语句(条件判断;字符串比较判断)
语法:switch(expression){case VALUE1 or /GEGEXP/:statement;case VALUE2 or /GEGEXP/:statement;...;default:statement}
7.6 break和continue
- break [n]:退出N次循环
- continue:跳出本轮循环,执行下一轮循环
7.7 next:提前结束对本行的处理,而直接进入下一行
示例: [root@localhost ~]# awk -F: '{if($3%2!=0)next;print $1,$3}' /etc/passwd
root 0
daemon 2
lp 4
shutdown 6
mail 8
games 12
ftp 14
systemd-network 192
libstoragemgmt 998
rpc 32
saslauth 996
rtkit 172
nfsnobody 65534
ntp 38
geoclue 994
sssd 992
gdm 42
sshd 74
avahi 70
tcpdump 72
inspur 1000
nginx 990
- array数组
关联数组:array[index-expression]
index-expression:索引表达式
<1>可使用任意字符串;字符串要使用双引号
<2>如果某数组元素实现不存在,在引用时,awk会自动创建此元素,并将其值初始化为“空串”;若要判断数组中是否存在某元素,要使用“index in array”
格式进行
<3>若要遍历数组中的每个元素,要使用for循环
注意:var会遍历array的每个元素
示例:
[root@localhost ~]# awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";print weekdays["tue"]}'
Tuesday
[root@localhost ~]# awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";print weekdays["mon"]}'
Monday
[root@localhost ~]# awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";{for(i in weekdays){print weekdays[i]}}}'
Tuesday
Monday
-
函数
内置函数:- 数值处理:rand():返回0和1之间一个随机数;
- 字符串处理:
length([s]):返回指定字符串的长度;
sub(r,s,[t]):以r表示的模式来查找t所表示的字符中的匹配的内容,并将其所以出现均替换为s所表示的内容;
gsub(r,s,[t]):以r标识的模式来查找t所表示的字符中匹配的内容,并将其所以出现均替换为s所表示的内容;
split(s,a,[,r]):以r为分隔符切割字符s,并将切割后的结果保存至a所表示的数组中;
练习1:统计netstat -tan中每个状态各出现多少次
[root@localhost ~]# netstat -tan | awk '/^tcp*/{state[$NF]++}END{for(i in state){print i,state[i]}}'
LISTEN 11
ESTABLISHED 1
练习2:统计ss -tan中状态各出现多少次
[root@localhost ~]# ss -tan|awk ' {state[$1]++}END{for(i in state)print i,state[i]}'
LISTEN 18
ESTAB 4
State 1
练习3:统计/usr/local/apache2/logs/access_log中的IP地址
[root@localhost ~]# awk '{pingnum[$1]++}END{for(i in pingnum)print i,pingnum[i]}' /usr/local/apache2/logs/access_log
192.168.1.104 15
练习4:统计 /etc/fstab 文件中文件系统类型出现的次数
[root@localhost ~]# awk '{for(i=1;i<=NF;i++){count[$i]++}}END{for(i in count){printf "%-15s %d\n",i,count[i] }}' /etc/fstab
man 1
and/or 1
maintained 1
xfs 3
/dev/mapper/centos-root 1
Accessible 1
\# 7
UUID=55bb7b0d-eb2d-454e-aaaa-fcbf3b0bedcd 1
are 1
defaults 4
blkid(8) 1
/ 1
0 8
See 1
1 1
Created 1
on 1
mount(8) 1
anaconda 1
fstab(5), 1
/boot 1
06:20:58 1
findfs(8), 1
/home 1
2018 1
'/dev/disk' 1
by 2
/etc/fstab 1
pages 1
UUID=0a8f2cdd-14bd-4df1-b23a-078f513ad814 1
more 1
info 1
swap 2
Jul 1
Sun 1
filesystems, 1
reference, 1
for 1
under 1
UUID=224da14b-890b-4f1a-8340-5a3ccc016085 1
练习5:统计netstat -tan中IP地址数量
[root@localhost ~]# netstat -tan | awk '/^tcp\>/{split($5,ip,":");count[ip[1]]++}END{for(i in count)print i,count[i]}'
192.168.1.104 1
0.0.0.0 7