From ac36c7022c16338ea1634b832b2cc1a183bcb71a Mon Sep 17 00:00:00 2001 From: wxin <15253413025@163.com> Date: Sun, 18 Aug 2024 19:49:59 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20Shell=20=E6=B5=81=E7=BC=96?= =?UTF-8?q?=E8=BE=91=E5=99=A8AWK.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ell 流编辑器AWK.md => Shell 流编辑器AWK.md | 4298 ++++++++--------- 1 file changed, 2149 insertions(+), 2149 deletions(-) rename 05-Shell 流编辑器AWK.md => Shell 流编辑器AWK.md (96%) diff --git a/05-Shell 流编辑器AWK.md b/Shell 流编辑器AWK.md similarity index 96% rename from 05-Shell 流编辑器AWK.md rename to Shell 流编辑器AWK.md index dfb2ad3..5030148 100644 --- a/05-Shell 流编辑器AWK.md +++ b/Shell 流编辑器AWK.md @@ -1,2149 +1,2149 @@ -# 05-Shell 流编辑器 AWK - -## 一、AWK 简介 - -AWK 是一种编程语言,用于在linux/unix下对文本和数据进行处理。数据可以来自标准输入、一个或多个文件,或其它命令的输出。它支持用户自定义函数和动态正则表达式等先进功能,是linux/unix下的一个强大编程工具。它在命令行中使用,但更多是作为脚本来使用。 - -AWK 逐行扫描文件,从第一行到最后一行,寻找匹配的特定模式的行,并在这些行上进行你想要的操作。如果没有指定处理动作,则把匹配的行显示到标准输出(屏幕),如果没有指定模式,则所有被操作所指定的行都被处理。awk分别代表其作者姓氏的第一个字母。因为它的作者是三个人,分别是Alfred Aho、Brian Kernighan、Peter Weinberger。gawk是awk的GNU版本,它提供了Bell实验室和GNU的一些扩展。 - -## 二、AWK 语法 - -```shell -awk [-F field-separator] 'commands' input-file(s) -awk [选项参数] 'commands' var=value file(s) -``` - -- commands 是真正 AWK 命令,[-F域分隔符]是可选的。 input-file(s) 是待处理的文件 - -- AWK 中,文件的每一行中,由域分隔符分开的每一项称为一个域。通常,在不指名-F域分隔符的情况下,默认的域分隔符是空格。 - -```shell -# awk -f awk-script-file input-file(s) -# awk [选项参数] -f scriptfile var=value file(s) -``` - -- -f 选项加载 awk-script-file 中的 awk 脚本,input-file(s) 是待处理的文件。 - -- 将所有的awk命令插入一个脚本文件,使用awk命令解释器作为脚本的首行,相当于shell脚本首行的:#!/bin/sh 可以换成:#!/bin/awk。通过执行脚本来调用 - -## 三、AWK 工作原理 - -AWK 工作流程可分为三个部分: - -- 读输入文件之前执行的代码段(由BEGIN关键字标识)。 -- 主循环执行输入文件的代码段。 -- 读输入文件之后的代码段(由END关键字标识)。 - -### 1、AWK 命令结构 - -```shell -awk 'BEGIN{ commands } pattern{ commands } END{ commands }' -``` - -下图是 AWK 的工作流程 - -![img](assets/20170719154838100.png) - -- 通过关键字 BEGIN 执行 BEGIN 块的内容,即 BEGIN 后花括号 **{}** 的内容。 -- 完成 BEGIN 块的执行,开始执行body块。 -- 读入有 **\n** 换行符分割的记录。 -- 将记录按指定的域分隔符划分域,填充域,**$0** 则表示所有域(即一行内容),**$1** 表示第一个域,**$n** 表示第 n 个域。 -- 依次执行各 BODY 块,pattern 部分匹配该行内容成功后,才会执行 awk-commands 的内容。 -- 循环读取并执行各行直到文件结束,完成body块执行。 -- 开始 END 块执行,END 块可以输出最终结果。 - -### 2、开始块(BEGIN) - -开始块的语法格式如下: - -```shell -BEGIN {awk-commands} -``` - -开始块就是在程序启动的时候执行的代码部分,并且它在整个过程中只执行一次。 - -一般情况下,我们可以在开始块中初始化一些变量。 - -BEGIN 是 AWK 的关键字,因此它必须是大写的。 - -**注意:**开始块部分是可选的,你的程序可以没有开始块部分。 - -### 3、主体块(BODY) - -主体部分的语法格式如下: - -```sh -/pattern/ {awk-commands} -``` - -对于每一个输入的行都会执行一次主体部分的命令。 - -默认情况下,对于输入的每一行,AWK 都会执行命令。但是,我们可以将其限定在指定的模式中。 - -**注意**:在主体块部分没有关键字存在。 - -### 4、结束块(END) - -结束块的语法格式如下: - -```shell -END {awk-commands} -``` - -结束块是在程序结束时执行的代码。 END 也是 AWK 的关键字,它也必须大写。 与开始块相似,结束块也是可选的。 - -### 5、实例 - -先创建一个名为 marks.txt 的文件。其中包括序列号、学生名字、课程名称与所得分数。 - -```shell -1) 张三 语文 80 -2) 李四 数学 90 -3) 王五 英语 87 -``` - -接下来,我们将使用 AWK 脚本来显示输出文件中的内容,同时输出表头信息。 - -```shell -[root@qfedu.com ~]# awk 'BEGIN{printf "序号\t名字\t课程\t分数\n"} {print}' marks.txt -``` - -执行以上命令,输出结果如下: - -```shell -序号 名字 课程 分数 -1) 张三 语文 80 -2) 李四 数学 90 -3) 王五 英语 87 -``` - -程序开始执行时,AWK 在开始块中输出表头信息。在主体块中,AWK 每读入一行就将读入的内容输出至标准输出流中,一直到整个文件被全部读入为止。 - -## 四、AWK 选项 - -- -F fs or --field-separator fs - 指定输入文件折分隔符,fs是一个字符串或者是一个正则表达式,如-F:。 -- -v var=value or --asign var=value - 赋值一个用户定义变量。 -- -f scripfile or --file scriptfile - 从脚本文件中读取awk命令。 -- -mf nnn and -mr nnn - 对nnn值设置内在限制,-mf选项限制分配给nnn的最大块数目;-mr选项限制记录的最大数目。这两个功能是Bell实验室版awk的扩展功能,在标准awk中不适用。 -- -W compact or --compat, -W traditional or --traditional - 在兼容模式下运行awk。所以gawk的行为和标准的awk完全一样,所有的awk扩展都被忽略。 -- -W copyleft or --copyleft, -W copyright or --copyright - 打印简短的版权信息。 -- -W help or --help, -W usage or --usage - 打印全部awk选项和每个选项的简短说明。 -- -W lint or --lint - 打印不能向传统unix平台移植的结构的警告。 -- -W lint-old or --lint-old - 打印关于不能向传统unix平台移植的结构的警告。 -- -W posix - 打开兼容模式。但有以下限制,不识别:/x、函数关键字、func、换码序列以及当fs是一个空格时,将新行作为一个域分隔符;操作符**和**=不能代替^和^=;fflush无效。 -- -W re-interval or --re-inerval - 允许间隔正则表达式的使用,参考(grep中的Posix字符类),如括号表达式[[:alpha:]]。 -- -W source program-text or --source program-text - 使用program-text作为源代码,可与-f命令混用。 -- -W version or --version - 打印bug报告信息的版本。 - -## 五、AWK 基本用法 - -1、创建 log.txt 文件 - -```shell -[root@qfedu.com ~]# cat log.txt -2 this is a test -3 Are you like awk -This's a test -10 There are orange,apple,mongo -``` - -2、行匹配语句(默认分隔符) - -```sh -awk '{[pattern] action}' {filenames} # 行匹配语句 awk '' 只能用单引号 -``` - -```shell -# 每行按空格或TAB分割,输出文本中的1、4项 -[root@qfedu.com ~]# awk '{print $1,$4}' log.txt -2 a -3 like -This's -10 orange,apple,mongo - -# 格式化输出 -[root@qfedu.com ~]# awk '{printf "%-8s %-10s\n",$1,$4}' log.txt -2 a -3 like -This's -10 orange,apple,mongo -``` - -3、指定分割字符 - -```shell -awk -F #-F相当于内置变量FS, 指定分割字符 -``` - -```shell -# 使用","分割 -[root@qfedu.com ~]# awk -F, '{print $1,$2}' log.txt -2 this is a test -3 Are you like awk -This's a test -10 There are orange apple - -# 或者使用内建变量 -[root@qfedu.com ~]# awk 'BEGIN{FS=","} {print $1,$2}' log.txt -2 this is a test -3 Are you like awk -This's a test -10 There are orange apple - -# 使用多个分隔符.先使用空格分割,然后对分割结果再使用","分割 -[root@qfedu.com ~]# awk -F '[ ,]' '{print $1,$2,$5}' log.txt -2 this test -3 Are awk -This's a -10 There apple -``` - -3、设置变量 - -```shell -awk -v #设置变量 -``` - -```shell -[root@qfedu.com ~]# awk -va=1 '{print $1,$1+a}' log.txt -2 3 -3 4 -This's 1 -10 11 - -[root@qfedu.com ~]# awk -va=1 -vb=s '{print $1,$1+a,$1b}' log.txt -2 3 2s -3 4 3s -This's 1 This'ss -10 11 10s -``` - -4、正则匹配 - -~ 表示模式开始。// 中是模式。 - -```shell -[root@qfedu.com ~]# awk '$1 ~ /bin/ {print $1,$4}' /etc/passwd -[root@qfedu.com ~]# awk -F: '$1 ~ /^alice/' /etc/passwd - -# 输出包含"root" 的行 -[root@qfedu.com ~]# awk '/root/ ' /etc/passwd -root:x:0:0:root:/root:/bin/bash -operator:x:11:0:operator:/root:/sbin/nologin - -# 匹配记录(整行): -[root@qfedu.com ~]# awk '/^alice/' /etc/passwd -[root@qfedu.com ~]# awk '$0 ~ /^alice/' /etc/passwd -[root@qfedu.com ~]# awk '!/alice/' passwd -[root@qfedu.com ~]# awk '$0 !~ /^alice/' /etc/passwd -``` - -5、忽略大小写 - -```shell -[root@qfedu.com ~]# awk 'BEGIN{IGNORECASE=1} /bin/' /etc/passwd -``` - -6、模式取反 - -```shell -[root@qfedu.com ~]# awk '$1 !~ /bin/ {print $1,$4}' /etc/passwd -[root@qfedu.com ~]# awk -F: '$NF !~ /bash$/' /etc/passwd -``` - -7、使用 AWK 脚本 - -```shell -awk -f {awk脚本} {文件名} -``` - -```shell -[root@qfedu.com ~]# awk -f cal.awk log.txt -``` - -## 六、格式化打印 - -- print 和 printf 都是打印输出的,不过两者用法和显示上有些不同而已。 - - -```shell -print 格式:print item1,item2, ... -printf格式:printf “FORMAT ”,item1,item2, ... -``` - -- 逗号为分隔符时,显示的是空格; - -- 分隔符分隔的字段(域)标记称为域标识,用$0,$1,$2,...,$n表示,其中$0 为所有域,$1就是表示第一个字段(域),以此类推; - -- 输出的各item可以字符串,也可以是数值,当前记录的字段,变量或awk 的表达式等; - -- 如果省略了item ,相当于print $0 - -- 对于printf来说,其中格式化字符串包括两部分内容: 一部分是正常字符,这些字符将按原样输出; 另一部分是格式化规定字符, 以 **%** 开始, 后跟一个或几个规定字符,用来确定输出内容格式,必须指定 FORMAT,即必须指出后面每个itemsN 的输出格式,**printf** 时默认是不会换行的,而 **print** 函数默认会在每行后面加上 **\n** 换行符 - -| **格式符** | **说明** | -| :--------- | :----------------------------------------------------------- | -| %d | 十进制有符号整数 | -| %u | 十进制无符号整数 | -| %f | 浮点数 | -| %s | 字符串 | -| %c | 单个字符 | -| %p | 指针的值 | -| %e | 指数形式的浮点数 | -| %x | %X 无符号以十六进制表示的整数 | -| %o | 无符号以八进制表示的整数 | -| %g | 自动选择合适的表示法 | -| %% | 显示%自身 | -| #[.#] | 第一个数字控制显示的宽度;第二个#表示小数点后精度,%3.1f | -| - | 左对齐(默认右对齐);%-15s,就是以左对齐方式显示15个字符长度 | -| + | 显示数值的正负符号 %+d | - -- 实例 - - -```sh -# print 函数 -[root@qfedu.com ~]# awk '{print "hello,awk"}' -[root@qfedu.com ~]# awk –F: '{print}' /etc/passwd -[root@qfedu.com ~]# awk –F: ‘{print “wang”}’ /etc/passwd -[root@qfedu.com ~]# awk –F: ‘{print $1}’ /etc/passwd -[root@qfedu.com ~]# awk –F: ‘{print $0}’ /etc/passwd -[root@qfedu.com ~]# awk –F: ‘{print $1”\t”$3}’ /etc/passwd -[root@qfedu.com ~]# date |awk '{print "Month: " $2 "\nYear: " $NF}' -[root@qfedu.com ~]# awk -F: '{print "username is: " $1 "\t uid is: " $3}' /etc/passwd -[root@qfedu.com ~]# awk -F: '{print "\tusername and uid: " $1,$3 "!"}' /etc/passwd - -# printf函数 -[root@qfedu.com ~]# tail –3 /etc/fstab |awk ‘{print $2,$4}’ -[root@qfedu.com ~]# awk -F: '{printf "%-15s %-10s %-15s\n", $1,$2,$3}' /etc/passwd -[root@qfedu.com ~]# awk -F: '{printf "|%-15s| %-10s| %-15s|\n", $1,$2,$3}' /etc/passwd -[root@qfedu.com ~]# awk -F: ‘{printf "%s",$1}’ /etc/passwd -[root@qfedu.com ~]# awk -F: ‘{printf "%s\n",$1}’ /etc/passwd -[root@qfedu.com ~]# awk -F: '{printf "%-20s %10d\n",$1,$3}' /etc/passwd -[root@qfedu.com ~]# awk -F: ‘{printf "Username: %s\n",$1}’ /etc/passwd -[root@qfedu.com ~]# awk -F: ‘{printf “Username: %s,UID:%d\n",$1,$3}’ /etc/passwd -[root@qfedu.com ~]# awk -F: ‘{printf "Username: %15s,UID:%d\n",$1,$3}’ /etc/passwd -[root@qfedu.com ~]# awk -F: ‘{printf "Username: %-15s,UID:%d\n",$1,$3}’ /etc/passwd -[root@qfedu.com ~]# lsmod | awk -v FS=" " 'BEGIN{printf "%s %26s %10s\n","Module","Size","Used by"}{printf "%-20s %13d %5s %s\n",$1,$2,$3,$4}' /proc/modules -``` - -## 七、AWK 运算符 - -| 运算符 | 描述 | -| :---------------------- | :------------------------------- | -| = += -= *= /= %= ^= **= | 赋值 | -| ?: | C条件表达式 | -| \|\| | 逻辑或 | -| && | 逻辑与 | -| ~ 和 !~ | 匹配正则表达式和不匹配正则表达式 | -| < <= > >= != == | 关系运算符 | -| 空格 | 连接 | -| + - | 加,减 | -| * / % | 乘,除与求余 | -| + - ! | 一元加,减和逻辑非 | -| ^ *** | 求幂 | -| ++ -- | 增加或减少,作为前缀或后缀 | -| $ | 字段引用 | -| in | 数组成员 | - -过滤第一列大于2的行 - -```shell -[root@qfedu.com ~]# awk '$1>2' log.txt -3 Are you like awk -This's a test -10 There are orange,apple,mongo -``` - -过滤第一列等于2的行 - -```shell -[root@qfedu.com ~]# awk '$1==2 {print $1,$3}' log.txt -2 is -``` - -过滤第一列大于2并且第二列等于'Are'的行 - -```shell -[root@qfedu.com ~]# awk '$1>2 && $2=="Are" {print $1,$2,$3}' log.txt -3 Are you -``` - -过滤练习 - -```shell -[root@qfedu.com ~]# awk -F: '$3 == 0' /etc/passwd -[root@qfedu.com ~]# awk -F: '$3 < 10' /etc/passwd -[root@qfedu.com ~]# awk -F: '$NF == "/bin/bash"' /etc/passwd -[root@qfedu.com ~]# awk -F: '$1 == "alice"' /etc/passwd -[root@qfedu.com ~]# awk -F: '$1 ~ /alic/ ' /etc/passwd -[root@qfedu.com ~]# awk -F: '$1 !~ /alic/ ' /etc/passwd -[root@qfedu.com ~]# df -P | grep '/' |awk '$4 > 25000' -``` - -## 八、AWK 变量 - -### 1、AWK 内置变量 - -| 变量 | 描述 | -| :---------- | :--------------------------------------------------------- | -| $n | 当前记录的第n个字段,字段间由FS分隔 | -| $0 | 完整的输入记录 | -| ARGC | 命令行参数的数目 | -| ARGIND | 命令行中当前文件的位置(从0开始算) | -| ARGV | 包含命令行参数的数组 | -| CONVFMT | 数字转换格式(默认值为%.6g)ENVIRON环境变量关联数组 | -| ERRNO | 最后一个系统错误的描述 | -| FIELDWIDTHS | 字段宽度列表(用空格键分隔) | -| FILENAME | 当前文件名 | -| FNR | 各文件分别计数的行号 | -| FS | 字段分隔符(默认是任何空格) | -| IGNORECASE | 如果为真,则进行忽略大小写的匹配 | -| NF | 一条记录的字段的数目 | -| NR | 已经读出的记录数,就是行号,从1开始 | -| OFMT | 数字的输出格式(默认值是%.6g) | -| OFS | 输出记录分隔符(输出换行符),输出时用指定的符号代替换行符 | -| ORS | 输出记录分隔符(默认值是一个换行符) | -| RLENGTH | 由match函数所匹配的字符串的长度 | -| RS | 记录分隔符(默认是一个换行符) | -| RSTART | 由match函数所匹配的字符串的第一个位置 | -| SUBSEP | 数组下标分隔符(默认值是/034) | - -```shell -[root@qfedu.com ~]# awk -F: '{print $0}' /etc/passwd # $0 -[root@qfedu.com ~]# awk -F: '{print NR, $0}' /etc/passwd /etc/hosts # NR -[root@qfedu.com ~]# awk -F: '{print FNR, $0}' /etc/passwd /etc/hosts # FNR -[root@qfedu.com ~]# awk -F: '{print $0,NF}' /etc/passwd # NF -[root@qfedu.com ~]# awk -F: '/alice/{print $1, $3}' /etc/passwd # FS -[root@qfedu.com ~]# awk -F'[ :\t]' '{print $1,$2,$3}' /etc/passwd -[root@qfedu.com ~]# awk 'BEGIN{FS=":"} {print $1,$3}' /etc/passwd -[root@qfedu.com ~]# awk -F: '/alice/{print $1,$2,$3,$4}' /etc/passwd # OFS -[root@qfedu.com ~]# awk 'BEGIN{FS=":"; OFS="+++"} /^root/{print $1,$2,$3,$4}' passwd -[root@qfedu.com ~]# awk -F: 'BEGIN{RS=" "} {print $0}' a.txt # RS -[root@qfedu.com ~]# awk -F: 'BEGIN{ORS=""} {print $0}' passwd # ORS -``` - -- 字段分隔符: FS OFS 默认空格或制表符 - -- 记录分隔符: RS ORS 默认换行符 - -```shell -# ORS 默认输出一条记录应该回车,加了一个空格 -[root@qfedu.com ~]# awk 'BEGIN{ORS=" "} {print $0}' /etc/passwd # 将文件每一行合并为一行 - -[root@qfedu.com ~]# head -1 /etc/passwd > passwd1 -[root@qfedu.com ~]# cat passwd1 -root:x:0:0:root:/root:/bin/bash -[root@qfedu.com ~]# awk 'BEGIN{RS=":"} {print $0}' passwd1 -root -x -0 -0 -root -/root -/bin/bash - -[root@qfedu.com ~]# awk 'BEGIN{RS=":"} {print $0}' passwd1 |grep -v '^$' > passwd2 - -# 输出顺序号 NR, 匹配文本行号 -[root@localhost ~]# awk '{print NR,FNR,$1,$2,$3}' /etc/passwd -1 1 root:x:0:0:root:/root:/bin/bash -2 2 bin:x:1:1:bin:/bin:/sbin/nologin -3 3 daemon:x:2:2:daemon:/sbin:/sbin/nologin -4 4 adm:x:3:4:adm:/var/adm:/sbin/nologin -5 5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin - -# 指定输出分割符 -[root@localhost ~]# awk '{print $1,$2,$5}' OFS=" $ " /etc/passwd -root:x:0:0:root:/root:/bin/bash $ $ -bin:x:1:1:bin:/bin:/sbin/nologin $ $ -daemon:x:2:2:daemon:/sbin:/sbin/nologin $ $ -adm:x:3:4:adm:/var/adm:/sbin/nologin $ $ -lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin $ $ -``` - -### 2、AWK 自定义变量(区分字符大小写) - -```shell -在'{...}'前,需要用-v var=value:awk -v var=value '{...}' -在program 中直接定义:awk '{var=vlue}' -``` - -### 3、AWK 使用外部变量 - -1、在双引号的情况下使用 - -```shell -[root@qfedu.com ~]# var="bash" -[root@qfedu.com ~]# echo "unix script" |awk "gsub(/unix/,\"$var\")" -bash script -``` - -2、在单引号的情况下使用 - -```shell -[root@qfedu.com ~]# var="bash" -[root@qfedu.com ~]# echo "unix script" |awk 'gsub(/unix/,"'"$var"'")' -bash script - -[root@qfedu.com ~]# df -h -Filesystem Size Used Avail Use% Mounted on -/dev/mapper/cl-root 2.8T 246G 2.5T 9% / -tmpfs 24G 20K 24G 1% /dev/shm -/dev/sda2 1014M 194M 821M 20% /boot - -[root@qfedu.com ~]# df -h |awk '{ if(int($5)>5){print $6":"$5} }' -/:9% -/boot:20% - -[root@qfedu.com ~]# i=10 -[root@qfedu.com ~]# df -h |awk '{ if(int($5)>'''$i'''){print $6":"$5} }' -/boot:20% -``` - -3、AWK 参数-v(建议) - -```shell -[root@qfedu.com ~]# echo "unix script" |awk -v var="bash" 'gsub(/unix/,var)' -bash script - -[root@qfedu.com ~]# awk -v user=root -F: '$1 == user' /etc/passwd -root:x:0:0:root:/root:/bin/bash -``` - -4、AWK 练习 - -```shell -[root@qfedu.com ~]# awk -F ':' '$3=="0"' /etc/passwd # 以冒号为分隔符,打印第三段是文本0的行,双引号代表字符,没有双引号代表数字 -[root@qfedu.com ~]# awk -F ':' '$3>="500"' /etc/passwd # 以冒号为分隔符,打印第三段大于等于字符串500的行 -[root@qfedu.com ~]# awk -F ':' '$3>=500' /etc/passwd # 以冒号为分隔符,打印第三段大于等于数字500的行 -[root@qfedu.com ~]# awk -F ':' '$7!="/sbin/nologin"' /etc/passwd # 以冒号为分隔符,打印第七段不为/sbin/nologin的行 -[root@qfedu.com ~]# awk -F ':' '$3<$4' /etc/passwd # 以冒号为分隔符,打印第三段小于第四段的行 -[root@qfedu.com ~]# awk -F ':' '$3>"5" && $3<"7"' /etc/passwd # 以冒号为分隔符,打印第三段大于字符5且第三段小于字符7的行 -[root@qfedu.com ~]# awk -F ':' '$3>1000 || $7=="/bin/bash"' /etc/passwd # 以冒号为分隔符,打印第三段大于1000或者第七段等于/bin/bash的行 -[root@qfedu.com ~]# head -5 /etc/passwd |awk -F ':' '{OFS="#"} {print $1,$3,$4}‘ # 以冒号为分隔符,打印每行第1、3、4段,并以井号间隔 -[root@qfedu.com ~]# awk -F ':' '{OFS="#"} {if ($3>1000) {print $1,$2,$3,$4}}' /etc/passwd # 以冒号为分隔符,如果第三段大于1000则打印第1、3、4段,并以井号间隔 -[root@qfedu.com ~]# head -n3 /etc/passwd | awk -F ':' '{print NF}‘ # 以冒号为分隔符,逐行打印该行列数 -[root@qfedu.com ~]# head -n3 /etc/passwd | awk -F ':' '{print NR}‘ # 以冒号为分隔符,逐行打印该行行数 -[root@qfedu.com ~]# awk 'NR>40' /etc/passwd # 打印行数大于40的行 -[root@qfedu.com ~]# awk -F ':' 'NR<20 && $1 ~ /roo/' /etc/passwd # 打印行数小于20并且第一段包含roo的行 -[root@qfedu.com ~]# head -n 3 /etc/passwd |awk -F ':' '$1="root"‘ # 以冒号为分隔符,给第一段赋值root,然后打印每一行 -[root@qfedu.com ~]# awk -F ':' '{(tot=tot+$3)}; END {print tot}' /etc/passwd # 逐行做完tot=tot+3的运算,最后打印出tot的值 -[root@qfedu.com ~]# awk -F ':' '{if ($1=="root") {print $0}}' /etc/passwd # 如果第一段是root,打印该行 - -[root@qfedu.com ~]# awk -v FS=':' '{print $1,FS,$3}’ /etc/passwd -[root@qfedu.com ~]# awk –F: '{print $1,$3,$7}’ /etc/passwd -[root@qfedu.com ~]# awk -v FS=‘:’ -v OFS=‘:’ '{print $1,$3,$7}’ /etc/passwd -[root@qfedu.com ~]# awk -v RS=' ' ‘{print }’ /etc/passwd -[root@qfedu.com ~]# awk -v RS="[[:space:]/=]" '{print }' /etc/fstab |sort -[root@qfedu.com ~]# awk -v RS=' ' -v ORS='###'‘{print }’ /etc/passwd -[root@qfedu.com ~]# awk -F: ‘{print NF}’ /etc/fstab, 引用内置变量不用$ -[root@qfedu.com ~]# awk -F: '{print $(NF-1)}' /etc/passwd -[root@qfedu.com ~]# awk '{print NR}' /etc/fstab ; awk 'END{print NR}' /etc/fstab -[root@qfedu.com ~]# awk '{print FNR}' /etc/fstab /etc/inittab -[root@qfedu.com ~]# awk '{print FNR}' /etc/fstab /etc/inittab -[root@qfedu.com ~]# awk '{print FILENAME}’ /etc/fstab -[root@qfedu.com ~]# awk '{print ARGC}’ /etc/fstab /etc/inittab -[root@qfedu.com ~]# awk ‘BEGIN {print ARGC}’ /etc/fstab /etc/inittab -[root@qfedu.com ~]# awk ‘BEGIN {print ARGV[0]}’ /etc/fstab /etc/inittab -[root@qfedu.com ~]# awk ‘BEGIN {print ARGV[1]}’ /etc/fstab /etc/inittab -[root@qfedu.com ~]# awk -v test='hello gawk' '{print test}' /etc/fstab -[root@qfedu.com ~]# awk -v test='hello gawk' 'BEGIN{print test}' -[root@qfedu.com ~]# awk 'BEGIN{test="hello,gawk";print test}' -[root@qfedu.com ~]# awk –F:‘{sex=“male”;print $1,sex,age;age=18}’ /etc/passwd -[root@qfedu.com ~]# awk -F: '{sex="male";age=18;print $1,sex,age}' /etc/passwd -[root@qfedu.com ~]# echo "{print script,\$1,\$2}" > awkscript -[root@qfedu.com ~]# awk -F: -f awkscript script=“awk” /etc/passwd -``` - -## 九、AWK 脚本 - -### 1、AWK 脚本定义格式 - -```shell -格式1: -BEGIN{} pattern{} END{} - -格式2: -#!/bin/awk -f -#add 'x' right -BEGIN{} pattern{} END{} -``` - -关于awk 脚本,需要注意两个关键词BEGIN和END。 - -- BEGIN{ 这里面放的是执行前的语句 } -- END {这里面放的是处理完所有的行后要执行的语句 } -- {这里面放的是处理每一行时要执行的语句} - -- 格式1假设为f1.awk文件,格式2假设为f2.awk文件 - -```shell -awk [-v var=value] f1.awk [file] -f2.awk [-v var=value] [var1=value1] [file] -``` - -- awk [-v var=value] f1.awk [file],把处理阶段放到一个文件而已,展开后就是普通的awk语句。 - -- f2.awk [-v var=value] [var1=value1] [file] 中 [-v var=value] 是在BEGIN之前设置的变量值,[var1=value1]是在BEGIN过程之后进行的,也就是说直到首行输入完成后,这个变量才可用。 - -### 2、AWK 脚本练习 - -#### 1、AWK 脚本实例1 - -1、创建一个文件(学生成绩表) - -```shell -[root@qfedu.com ~]# cat score.txt -Marry 2143 78 84 77 -Jack 2321 66 78 45 -Tom 2122 48 77 71 -Mike 2537 87 97 95 -Bob 2415 40 57 62 -``` - -2、定义 awk 脚本 - -```shell -[root@qfedu.com ~]# cat cal.awk -#!/bin/awk -f -#运行前 -BEGIN { - math = 0 - english = 0 - computer = 0 - - printf "NAME NO. MATH ENGLISH COMPUTER TOTAL\n" - printf "---------------------------------------------\n" -} -#运行中 -{ - math+=$3 - english+=$4 - computer+=$5 - printf "%-6s %-6s %4d %8d %8d %8d\n", $1, $2, $3,$4,$5, $3+$4+$5 -} -#运行后 -END { - printf "---------------------------------------------\n" - printf " TOTAL:%10d %8d %8d \n", math, english, computer - printf "AVERAGE:%10.2f %8.2f %8.2f\n", math/NR, english/NR, computer/NR -} - -[root@qfedu.com ~]# awk -f cal.awk score.txt -NAME NO. MATH ENGLISH COMPUTER TOTAL ---------------------------------------------- -Marry 2143 78 84 77 239 -Jack 2321 66 78 45 189 -Tom 2122 48 77 71 196 -Mike 2537 87 97 95 279 -Bob 2415 40 57 62 159 ---------------------------------------------- - TOTAL: 319 393 350 -AVERAGE: 63.80 78.60 70.00 -``` - -2、AWK 脚本实例2 - -```shell -cat f1.awk - {if($3>=1000)print $1,$3} -awk -F: -f f1.awk /etc/passwd - -cat f2.awk - #!/bin/awk –f - # this is a awk script - {if($3>=1000)print $1,$3} - # chmod +x f2.awk -f2.awk –F: /etc/passwd - -cat test.awk - #!/bin/awk –f - {if($3 >=min && $3<=max)print $1,$3} - #chmod +x test.awk -test.awk -F: min=100 max=200 /etc/passwd -``` - -## 十、AWK 流程控制 - -### 1、AWK 条件语句 - -#### 1、IF 语句 - -##### 1、IF 条件语句语法格式 - -```shell -if (condition) - action -``` - -使用花括号语法格式 - -```shell -if (condition) -{ - action1; - action2; - ... -} - -{if(表达式){语句1;语句2;...}} -``` - -##### 2、IF 语句实例 - -###### 1、判断数字是奇数还是偶数 - -```shell -[root@qfedu.com ~]# awk 'BEGIN {num = 10; if (num % 2 == 0) printf "%d 是偶数\n", num }' -10 是偶数 -``` - -###### 2、判断 root 是不是 administrator - -```shell -[root@qfedu.com ~]# awk -F: '{if($3==0) {print $1 " is administrator."}}' /etc/passwd -root is administrator. -``` - -###### 3、 统计系统用户数 - -```shell -[root@qfedu.com ~]# awk -F: '{if($3>0 && $3<1000){count++;}} END{print count}' /etc/passwd   -20 -``` - -#### 2、IF - ELSE 语句 - -##### 1、IF - ELSE 条件语句语法格式 - -```shell -if (condition) - action1 -else - action2 -``` - -使用花括号语法格式 - -```shell -{if (condition) -{ - action1; - action2; - ... -} -else -{ - action1; - action2; - ... -}} - -{if(表达式){语句1;语句2;...}else{语句1;语句2;...}} -``` - -##### 2、IF - ELSE 语句实例 - -###### 1、判断数字是奇数还是偶数 - -```shell -[root@qfedu.com ~]# awk 'BEGIN { - num = 11; - if (num % 2 == 0) printf "%d 是偶数\n", num; - else printf "%d 是奇数\n", num -}' - -11 是奇数 -``` - -###### 2、判断用户为root就打印用户名否则打印shell类型 - -```shell -[root@qfedu.com ~]# awk -F: '{if($3==0){print $1} else {print $7}}' /etc/passwd -root -/sbin/nologin -/sbin/nologin -/sbin/nologin -/sbin/nologin -/bin/sync -/sbin/shutdown -``` - -###### 3、统计管理员数量和系统用户数量 - -```shell -[root@qfedu.com ~]# awk -F: '{if($3==0){count++} else{i++}} END{print "管理员个数: "count ; print "系统用户数: "i}' /etc/passwd -管理员个数: 1 -系统用户数: 20 -``` - -#### 3、IF - ELSE - IF 语句 - -##### 1、IF - ELSE - IF条件语句语法格式 - -```shell -{if (condition1) -{ - action1; - action2; - ... -} -else if (condition2) -{ - action1; - action2; - ... -} -else if (condition3) -{ - action1; - action2; - ... -} -else -{ - action1; - action2; - ... -}} - -{if(表达式1){语句1;语句2;...}else if(表达式2){语句1;语句2;...}else if(表达式3){语句1;语句2;...}else{语句1;语句2;...}} -``` - -##### 2、IF - ELSE - IF 语句实例 - -###### 1、多级判断结果 - -```shell -[root@qfedu.com ~]# awk 'BEGIN { -a=30; -if (a==10) - print "a = 10"; -else if (a == 20) - print "a = 20"; -else if (a == 30) - print "a = 30"; -}' - -a = 30 -``` - -###### 2、统计管理员,系统,普通用户数量 - -```shell -[root@qfedu.com ~]# awk -F: '{if($3==0){i++} else if($3>999){k++} else{j++}} END{print i; print k; print j}' /etc/passwd -1 - -20 - -[root@qfedu.com ~]# awk -F: '{if($3==0){i++} else if($3>999){k++} else{j++}} END{print "管理员个数: "i; print "普通用个数: "k; print "系统用户: "j}' /etc/passwd -管理员个数: 1 -普通用个数: -系统用户: 20 -``` - -### 2、AWK 循环 - -#### 1、For 循环 - -##### 1、For 循环的语法 - -```shell -for(variable addignment; condition; iteration peocess) -{ - statement1 - statement2 - ... -} -``` - -for 语句首先执行初始化动作( initialisation ),然后再检查条件( condition )。如果条件为真,则执行动作( action ),然后执行递增( increment )或者递减( decrement )操作。只要条件为 true 循环就会一直执行。每次循环结束都会进条件检查,若条件为 false 则结束循环。 - -##### 2、For 循环实例 - -###### 1、For 循环输出数字 1 至 5 - -```shell -[root@qfedu.com ~]# awk 'BEGIN { for (i = 1; i <= 5; ++i) print i }' -1 -2 -3 -4 -5 -``` - -###### 2、For 循环输出数字 1 至 9 的奇数之和 - -```shell -[root@qfedu.com ~]# echo "hello" | awk ' -{ - total = 0 - for(i=1; i<10; i++) - { - if(i % 2 == 0) - { - continue - } - total = total + i - } - print "total=", total -}' -``` - -###### 3、将每行打印10次 - -```shell -[root@qfedu.com ~]# awk -F: '{ for(i=1;i<=10;i++) {print $0} }' /etc/passwd -root:x:0:0:root:/root:/bin/bash -root:x:0:0:root:/root:/bin/bash -root:x:0:0:root:/root:/bin/bash -root:x:0:0:root:/root:/bin/bash -root:x:0:0:root:/root:/bin/bash -root:x:0:0:root:/root:/bin/bash -root:x:0:0:root:/root:/bin/bash -root:x:0:0:root:/root:/bin/bash -root:x:0:0:root:/root:/bin/bash -root:x:0:0:root:/root:/bin/bash -``` - -###### 4、分别打印每行的每列 - -```shell -[root@qfedu.com ~]# awk -F: '{ for(i=1;i<=NF;i++) {print $i} }' /etc/passwd -root -x -0 -0 -root -/root -/bin/bash -bin -x -1 -1 -bin -/bin -/sbin/nologin -``` - -#### 2、While 循环 - -##### 1、While 循环的语法 - -```shell -while(condition) -{ - statement1 - statement2 - ... -} -``` - -While 循环首先检查条件 condition 是否为 true ,若条件为 true 则执行动作 action。此过程一直重复直到条件 condition 为 flase 才停止。 - -##### 2、While 循环实例 - -###### 1、While 循环输出数字 1 到 5 - -```shell -[root@qfedu.com ~]# awk 'BEGIN {i = 1; while (i < 6) { print i; ++i } }' -1 -2 -3 -4 -5 - -[root@qfedu.com ~]# awk 'BEGIN{ i=1; while(i<=5){print i; i++} }' -1 -2 -3 -4 -5 -``` - -###### 2、While 循环输出数字 1 至 9 的奇数之和 - -```shell -[root@qfedu.com ~]# echo "hello" | awk ' -{ - total = 0 - i = 1 - while(i < 10) - { - if(i % 2 == 0) - { - i++ - continue - } - total = total + i - i++ - } - print "total=", total -}' -``` - -###### 3、打印第一行的前七列 - -```shell -[root@qfedu.com ~]# awk -F: '/^root/{i=1; while(i<=7){print $i; i++}}' /etc/passwd -root -x -0 -0 -root -/root -/bin/bash -``` - -###### 4、分别打印每行的每列 - -```shell -[root@qfedu.com ~]# awk '{i=1; while(i<=NF){print $i; i++}}' /etc/hosts -127.0.0.1 -localhost -localhost.localdomain -localhost4 -localhost4.localdomain4 -::1 -localhost -localhost.localdomain -localhost6 -localhost6.localdomain6 -``` - -###### 5、将每行打印10次 - -```shell -[root@qfedu.com ~]# awk -F: '{i=1; while(i<=10) {print $0; i++}}' /etc/passwd -root:x:0:0:root:/root:/bin/bash -root:x:0:0:root:/root:/bin/bash -root:x:0:0:root:/root:/bin/bash -root:x:0:0:root:/root:/bin/bash -root:x:0:0:root:/root:/bin/bash -root:x:0:0:root:/root:/bin/bash -root:x:0:0:root:/root:/bin/bash -root:x:0:0:root:/root:/bin/bash -root:x:0:0:root:/root:/bin/bash -root:x:0:0:root:/root:/bin/bash -``` - -#### 3、Break 结束循环 - -##### 1、Break 结束循环实例 - -break[n]:当第n次循环到来后,结束整个循环,n=0就是指本次循环 - -当计算的和大于 50 的时候使用 break 结束循环: - -```shell -[root@qfedu.com ~]# awk 'BEGIN { - sum = 0; for (i = 0; i < 20; ++i) { - sum += i; if (sum > 50) break; else print "Sum =", sum - } -}' - -Sum = 0 -Sum = 1 -Sum = 3 -Sum = 6 -Sum = 10 -Sum = 15 -Sum = 21 -Sum = 28 -Sum = 36 -Sum = 45 -``` - -#### 4、Continue 跳出本次循环 - -Continue 语句用于在循环体内部结束本次循环,从而直接进入下一次循环迭代。 - -Continue[n]:满足条件后,直接进行第n次循环,本次循环不在进行,n=0也就是提前结束本次循环而直接进入下一轮 - -输出 1 到 20 之间的偶数: - -```shell -[root@qfedu.com ~]# awk 'BEGIN {for (i = 1; i <= 20; ++i) {if (i % 2 == 0) print i ; else continue} }' -2 -4 -6 -8 -10 -12 -14 -16 -18 -20 -``` - -#### 5、Exit 结束脚本程序 - -Exit 用于结束脚本程序的执行。 - -该函数接受一个整数作为参数表示 AWK 进程结束状态。 如果没有提供该参数,其默认状态为 0。 - -当和大于 50 时结束 AWK 程序。 - -```shell -[root@qfedu.com ~]# awk 'BEGIN { - sum = 0; for (i = 0; i < 20; ++i) { - sum += i; if (sum > 50) exit(10); else print "Sum =", sum - } -}' - -Sum = 0 -Sum = 1 -Sum = 3 -Sum = 6 -Sum = 10 -Sum = 15 -Sum = 21 -Sum = 28 -Sum = 36 -Sum = 45 -``` - -检查脚本执行后的返回状态 - -```shell -[root@qfedu.com ~]# echo $? -10 -``` - -#### 6、Next 停止处理 - -next:提前结束对本行的处理动作而直接进入下一行处理 - - -```shell -[root@qfedu.com ~]# awk -F: '{if($3%2!=0) next; print $1,$3}' /etc/passwd -``` - -## 十一、AWK 数组 - -AWK 可以使用关联数组这种数据结构,索引可以是数字或字符串。 - -AWK关联数 组也不需要提前声明其大小,因为它在运行时可以自动的增大或减小。 - -### 1、数组语法格式 - -```shell -array_name[index]=value -``` - -- array_name:数组的名称 -- index:数组索引 -- value:数组中元素所赋予的值 - -### 2、创建数组 - -定义了一个站点(sites)数组,该数组的索引为网站英文简称,值为网站访问地址。 - -```shell -[root@qfedu.com ~]# awk 'BEGIN { -sites["qfedu"]="www.qfedu.com"; -sites["google"]="www.google.com" -print sites["qfedu"] "\n" sites["google"] -}' -www.qfedu.com -www.google.com -``` - -### 3、访问数组元素 - -#### 1、访问数组元素语法格式 - -```shell -array_name[index] -``` - -#### 2、访问数组元素 - -```sh -[root@qfedu.com ~]# awk -F: '{username[++i]=$1} END{print username[1]}' /etc/passwd -root -[root@qfedu.com ~]# awk -F: '{username[i++]=$1} END{print username[1]}' /etc/passwd -bin -[root@qfedu.com ~]# awk -F: '{username[i++]=$1} END{print username[0]}' /etc/passwd -root -``` - -#### 3、按元数个数遍历 - -```shell -[root@qfedu.com ~]# awk -F: '{username[x++]=$1} END{for(i=0;iv2?var=v1:var=v2 - return var - } - BEGIN{a=3;b=2;print max(a,b)} -awk –f fun.awk -``` - -## 十三、课下练习 - -1、AWK 日志分析统计 - -```shell -# 统计一个时间范围内访(pv)问量 -[root@qfedu.com ~]# grep '01/Sep/2017' sz.mobiletrain.org.log | wc -l -[root@qfedu.com ~]# awk '$4>="[05/Sep/2017:08:00:00" && $4<="[05/Sep/2017:09:00:00" {print $0}' sz.mobiletrain.org.log | wc -l - -# 统计一个时间范围内访问量前10的ip -[root@qfedu.com ~]# grep '05/Sep/2017' cd.mobiletrain.org.log | awk '{ips[$1]++} END{ for(i in ips){print i ,ips[i]}}' | sort -k2 -rn | head - -[root@qfedu.com ~]# awk '/05\/Sep\/2017/ {ips[$1]++} END{ for(i in ips){print i ,ips[i]}}' cd.mobiletrain.org.log | sort -k2 -rn | head - -# 统计一个时间范围内访问前10的页面 -[root@qfedu.com ~]# grep '05/Sep/2017' cd.mobiletrain.org.log | awk '{ urls[$7]++} END{for(i in urls){print urls[i],i}}'|sort -k1 -rn |head - -[root@qfedu.com ~]# awk '/05\/Sep\/2017/ { urls[$7]++} END{for(i in urls){print urls[i],i}}' cd.mobiletrain.org.log |sort -k1 -rn |head - -# 统计一个时间范围内访问大于100次的ip -[root@qfedu.com ~]# grep '05/Sep/2017' sz.mobiletrain.org.log | awk '{ ips[$1]++ } END{for (i in ips) {if(ips[i]>100) {print i,ips[i]}}}' -[root@qfedu.com ~]# awk '/05\/Sep\/2017/ { ips[$1]++ } END{for (i in ips) {if(ips[i]>100) {print i,ips[i]}}}' sz.mobiletrain.org.log - -# 统计一个时间范围访问前10的url -[root@qfedu.com ~]# awk '/05\/Sep\/2017/{urls[$7]++} END{for(i in urls){print i,urls[i]}}' sz.mobiletrain.org.log |sort -k2rn |head - -# 统计一个时间范围内url访问总大小前10的url -[root@qfedu.com ~]# grep '05/Sep/2017' sz.mobiletrain.org.log | awk '{ urls[$7]++; size[$7]+=$10} END { for(i in urls ) { print urls[i],size[i],i}}'| sort -k1 -rn |head - -[root@qfedu.com ~]# awk '/05\/Sep\/2017/{size[$7]+=$10} END{for(i in size){print i,size[i]}}' sz.mobiletrain.org.log |sort -k2rn |head - -# 统计一个时间范围内每个访问ip的状态码数量 -[root@qfedu.com ~]# grep '05/Sep/2017' sz.mobiletrain.org.log | awk '{ ip_code[ $1" "$9]++} END{ for(i in ip_code) {print i,ip_code[i]}}'| sort -k1 -rn | head - -[root@qfedu.com ~]# awk '/05\/Sep\/2017/{ip_code[$1" "$9]++} END{for(i in ip_code){print i,ip_code[i]}}' sz.mobiletrain.org.log |sort -k1rn |head - -# 统计一个时间范围内访问状态码时404的ip -[root@qfedu.com ~]# grep '05/Sep/2017' sz.mobiletrain.org.log | awk '{if($9="404"){ip_code[$1" "$9]++}} END{for(i in ip_code){print i,ip_code[i]}}'|sort -k3 -rn - -[root@qfedu.com ~]# awk '$4>="[05/Sep/2017:08:00:00" && $4<="[05/Sep/2017:09:00:00" {if($9="404"){ip_code[$1" "$9]++}} END{for(i in ip_code){print i,ip_code[i]}}' sz.mobiletrain.org.log |sort -k3 -rn - -[root@qfedu.com ~]# awk '/05\/Sep\/2017/{if($9=="404"){ip_code[$1" "$9]++}} END{for(i in ip_code){print i,ip_code[i]}}' sz.mobiletrain.org.log |sort -k3rn |head - -# 统计前一分钟的访问量 -[root@qfedu.com ~]# date=$(date -d '1 minute' +%d/%b/%Y:%H:%M); awk -v date=$date '$0 ~ date {i++} END{print i}' sz.mobiletrain.org.log -# 统计一个时间范围内出现的各种状态码 -[root@qfedu.com ~]# grep '05/Sep/2017' sz.mobiletrain.org.log | awk '{code[$9]++} END{for(i in code){print i, code[i]}}' -[root@qfedu.com ~]# awk '/05\/Sep\/2017/ {code[$9]++}END{for(i in code){print i ,code[i]}}' sz.mobiletrain.org.log -[root@qfedu.com ~]# grep '05/Sep/2017' sz.mobiletrain.org.log | awk '{code[$9]++; total++} END{for(i in code){printf i" "; printf code[i]"\t";printf"%.2f", code[i]/total*100;print"%"}}' - -[root@qfedu.com ~]# awk '/05\/Sep\/2017/{code[$9]++; total++} END{for(i in code){printf i " "; printf code[i]"\t"; printf"%.2f",code[i]/total*100;print"%"}}' sz.mobiletrain.org.log -``` - -2、AWK 统计 tcp 连接 - -```shell -[root@qfedu.com ~]# ss -an | grep ^tcp|awk '{tcp_connect_status[$2]++}END{for(i in tcp_connect_status) {print i, tcp_connect_status[i]}}' -``` - -3、AWK 获取硬件信息 - -```shell -#!/bin/bash -yum install hdparm dmidecode pciutils -y -echo -echo "###### CPU #######" -echo -cat /proc/cpuinfo | grep "model name"| awk -F ":" '{print $2}'| uniq -f 1 -cat /proc/cpuinfo | grep "cpu cores"| awk -F ":" '{print " CPU ="$2}'| uniq -f 1 -echo -echo "###### Hard Disk ######" -echo -hdparm -i /dev/sda | grep -i "model"| awk -F"-" '{print $1}'| awk -F "=" '{print $2}' -fdisk -l | grep "/dev/sda"| awk -F "," 'NR==1{print $1}' -echo -df -h -echo -echo "###### Memory ######" -echo -dmidecode -t memory | grep -i "maximum capacity" -dmidecode -t memory | grep -i "number of devices" -echo -dmidecode -t memory | grep -i "size"| awk -F ":" 'NR==1{print " Capacity 1" $1":",$2}' -dmidecode -t memory | grep -i "speed"| awk 'NR==1' -dmidecode -t memory | grep -i "type:"| uniq -f 1 -dmidecode -t memory | grep -i "size"| awk -F ":" 'NR==2{print " Capacity 2" $1":",$2}' -dmidecode -t memory | grep -i "speed"| awk 'NR==2' -dmidecode -t memory | grep -i "type:"| uniq -f 1 -dmidecode -t memory | grep -i "size"| awk -F ":" 'NR==3{print " Capacity 3" $1":",$2}' -dmidecode -t memory | grep -i "speed"| awk 'NR==3' -dmidecode -t memory | grep -i "type:"| uniq -f 1 -dmidecode -t memory | grep -i "size"| awk -F ":" 'NR==4{print " Capacity 4" $1":",$2}' -dmidecode -t memory | grep -i "speed"| awk 'NR==4' -dmidecode -t memory | grep -i "type:"| uniq -f 1 -echo -free -m -echo -echo "###### Mianboard ######" -echo -dmidecode -q | grep -i "product name"| awk -F":" 'NR==1{print "Server Model" ":",$2}' -dmidecode -q | grep -i "Manufacturer"| awk -F":" 'NR==1{print "Brand" ":",$2}' -dmidecode -q | grep -i "product name"| awk -F":" 'NR==2{print "Mainboard Model" ":",$2}' -echo -echo "###### Network Card ######" -echo -lspci | grep -i eth | awk 'NR==1'| awk -F ":" '{print $3}' -echo -echo "###### Operating System ######" -echo -cat /etc/issue | awk 'NR==1' -uname -r | awk '{print "kernel: "$1}' -echo -``` - -4、AWK 获取系统状态信息 - -```shell -#!/bin/bash -#show system information -PS3="Your choice is: " -os_check() { - if [ -e /etc/redhat-release ]; then - REDHAT=`cat /etc/redhat-release |cut -d' ' -f1` - else - DEBIAN=`cat /etc/issue |cut -d' ' -f1` - fi - - if [ "$REDHAT" == "CentOS" -o "$REDHAT" == "Red" ]; then - P_M=yum - elif [ "$DEBIAN" == "Ubuntu" -o "$DEBIAN" == "ubutnu" ]; then - P_M=apt-get - else - Operating system does not support. - exit 1 - fi -} - -if [ $LOGNAME != root ]; then - echo "Please use the root account operation." - exit 1 -fi - -if ! which vmstat &>/dev/null; then - echo "vmstat command not found, now the install." - sleep 1 - os_check - $P_M install procps -y - echo "-----------------------------------------------------------------------" -fi - -which iostat &>/dev/null -if [ $? -ne 0 ]; then - echo "iostat command not found, now the install." - sleep 1 - os_check - $P_M install sysstat -y - echo "-----------------------------------------------------------------------" -fi - -while true; do - select input in cpu_load disk_load disk_use disk_inode mem_use tcp_status cpu_top10 mem_top10 traffic quit; do - case $input in - cpu_load) - #CPU利用率与负载 - echo "---------------------------------------" - i=1 - while [[ $i -le 3 ]]; do - echo -e "\033[32m 参考值${i}\033[0m" - UTIL=`vmstat |awk '{if(NR==3)print 100-$15"%"}'` - USER=`vmstat |awk '{if(NR==3)print $13"%"}'` - SYS=`vmstat |awk '{if(NR==3)print $14"%"}'` - IOWAIT=`vmstat |awk '{if(NR==3)print $16"%"}'` - echo "Util: $UTIL" - echo "User use: $USER" - echo "System use: $SYS" - echo "I/O wait: $IOWAIT" - let i++ - sleep 1 - done - echo "---------------------------------------" - break - ;; - disk_load) - #硬盘I/O负载 - echo "---------------------------------------" - i=1 - while [[ $i -le 3 ]]; do - echo -e "\033[32m 参考值${i}\033[0m" - UTIL=`iostat -x -k |awk '/^[v|s]/{OFS=": ";print $1,$NF"%"}'` - READ=`iostat -x -k |awk '/^[v|s]/{OFS=": ";print $1,$6"KB"}'` - WRITE=`iostat -x -k |awk '/^[v|s]/{OFS=": ";print $1,$7"KB"}'` - IOWAIT=`vmstat |awk '{if(NR==3)print $16"%"}'` - echo -e "Util:" - echo -e "${UTIL}" - echo -e "I/O Wait: $IOWAIT" - echo -e "Read/s:\n$READ" - echo -e "Write/s:\n$WRITE" - i=$(($i+1)) - sleep 1 - done - echo "---------------------------------------" - break - ;; - disk_use) - #硬盘利用率 - DISK_LOG=/tmp/disk_use.tmp - DISK_TOTAL=`fdisk -l |awk '/^Disk.*bytes/ && /\/dev/{printf $2" ";printf "%d",$3;print "GB"}'` - USE_RATE=`df -h |awk '/^\/dev/{print int($5)}'` - for i in $USE_RATE; do - if [ $i -gt 90 ];then - PART=`df -h |awk '{if(int($5)=='''$i''') print $6}'` - echo "$PART = ${i}%" >> $DISK_LOG - fi - done - echo "---------------------------------------" - echo -e "Disk total:\n${DISK_TOTAL}" - if [ -f $DISK_LOG ]; then - echo "---------------------------------------" - cat $DISK_LOG - echo "---------------------------------------" - rm -f $DISK_LOG - else - echo "---------------------------------------" - echo "Disk use rate no than 90% of the partition." - echo "---------------------------------------" - fi - break - ;; - disk_inode) - #硬盘inode利用率 - INODE_LOG=/tmp/inode_use.tmp - INODE_USE=`df -i |awk '/^\/dev/{print int($5)}'` - for i in $INODE_USE; do - if [ $i -gt 90 ]; then - PART=`df -h |awk '{if(int($5)=='''$i''') print $6}'` - echo "$PART = ${i}%" >> $INODE_LOG - fi - done - if [ -f $INODE_LOG ]; then - echo "---------------------------------------" - cat $INODE_LOG - rm -f $INODE_LOG - else - echo "---------------------------------------" - echo "Inode use rate no than 90% of the partition." - echo "---------------------------------------" - fi - break - ;; - mem_use) - #内存利用率 - echo "---------------------------------------" - MEM_TOTAL=`free -m |awk '{if(NR==2)printf "%.1f",$2/1024}END{print "G"}'` - USE=`free -m |awk '{if(NR==2) printf "%.1f",$3/1024}END{print "G"}'` - FREE=`free -m |awk '{if(NR==2) printf "%.1f",$4/1024}END{print "G"}'` - CACHE=`free -m |awk '{if(NR==2) printf "%.1f",$6/1024}END{print "G"}'` - echo -e "Total: $MEM_TOTAL" - echo -e "Use: $USE" - echo -e "Free: $FREE" - echo -e "Cache: $CACHE" - echo "---------------------------------------" - break - ;; - tcp_status) - #网络连接状态 - echo "---------------------------------------" - COUNT=`ss -ant |awk '!/State/{status[$1]++}END{for(i in status) print i,status[i]}'` - echo -e "TCP connection status:\n$COUNT" - echo "---------------------------------------" - ;; - cpu_top10) - #占用CPU高的前10个进程 - echo "---------------------------------------" - CPU_LOG=/tmp/cpu_top.tmp - i=1 - while [[ $i -le 3 ]]; do - #ps aux |awk '{if($3>0.1)print "CPU: "$3"% -->",$11,$12,$13,$14,$15,$16,"(PID:"$2")" |"sort -k2 -nr |head -n 10"}' > $CPU_LOG - ps aux |awk '{if($3>0.1){{printf "PID: "$2" CPU: "$3"% --> "}for(i=11;i<=NF;i++)if(i==NF)printf $i"\n";else printf $i}}' |sort -k4 -nr |head -10 > $CPU_LOG - #循环从11列(进程名)开始打印,如果i等于最后一行,就打印i的列并换行,否则就打印i的列 - if [[ -n `cat $CPU_LOG` ]]; then - echo -e "\033[32m 参考值${i}\033[0m" - cat $CPU_LOG - > $CPU_LOG - else - echo "No process using the CPU." - break - fi - let i++ - sleep 1 - done - echo "---------------------------------------" - break - ;; - mem_top10) - #占用内存高的前10个进程 - echo "---------------------------------------" - MEM_LOG=/tmp/mem_top.tmp - i=1 - while [[ $i -le 3 ]]; do - #ps aux |awk '{if($4>0.1)print "Memory: "$4"% -->",$11,$12,$13,$14,$15,$16,"(PID:"$2")" |"sort -k2 -nr |head -n 10"}' > $MEM_LOG - ps aux |awk '{if($4>0.1){{printf "PID: "$2" Memory: "$4"% --> "}for(i=11;i<=NF;i++)if(i==NF)printf $i"\n";else printf $i}}' |sort -k4 -nr |head -10 > $MEM_LOG - if [[ -n `cat $MEM_LOG` ]]; then - echo -e "\033[32m 参考值${i}\033[0m" - cat $MEM_LOG - > $MEM_LOG - else - echo "No process using the Memory." - break - fi - i=$(($i+1)) - sleep 1 - done - echo "---------------------------------------" - break - ;; - traffic) - #查看网络流量 - while true; do - read -p "Please enter the network card name(eth[0-9] or em[0-9] or team[0-9]): " eth - if [ `ifconfig |grep -c "\<$eth\>"` -eq 1 ]; then - break - else - echo "Input format error or Don't have the card name, please input again." - fi - done - echo "---------------------------------------" - echo -e " In ------ Out" - i=1 - while [[ $i -le 3 ]]; do - #CentOS6和CentOS7 ifconfig输出进出流量信息位置不同: - #CentOS6中RX与TX行号等于8 - #CentOS7中RX行号是5,TX行号是7 - - OLD_IN=`ifconfig $eth |awk -F'[: ]+' '/bytes/{if(NR==8)print $4;else if(NR==5)print $6}'` - OLD_OUT=`ifconfig $eth |awk -F'[: ]+' '/bytes/{if(NR==8)print $9;else if(NR==7)print $6}'` - sleep 1 - NEW_IN=`ifconfig $eth |awk -F'[: ]+' '/bytes/{if(NR==8)print $4;else if(NR==5)print $6}'` - NEW_OUT=`ifconfig $eth |awk -F'[: ]+' '/bytes/{if(NR==8)print $9;else if(NR==7)print $6}'` - - IN=`awk 'BEGIN{printf "%.1f\n",'$((${NEW_IN}-${OLD_IN}))'/1024/128}'` - OUT=`awk 'BEGIN{printf "%.1f\n",'$((${NEW_OUT}-${OLD_OUT}))'/1024/128}'` - echo "${IN}MB/s ${OUT}MB/s" - - i=$(($i+1)) - sleep 1 - done - echo "---------------------------------------" - break - ;; - quit) - exit 0 - ;; - *) - echo "---------------------------------------" - echo "Please enter the number." - echo "---------------------------------------" - break - ;; - esac - done -done - -``` - -5、Linux 系统初始化脚本 - -```shell -#!/bin/bash - -# get os version -RELEASEVER=$(rpm -q --qf "%{VERSION}" $(rpm -q --whatprovides redhat-release)) - -# configure yum source -cd /etc/yum.repos.d/ -mkdir /etc/yum.repos.d/bak -mv /etc/yum.repos.d/*.repo /etc/yum.repos.d/bak -if [ $RELEASEVER == 6 ];then -    curl http://mirrors.163.com/.help/CentOS6-Base-163.repo > qf.repo -fi -if [ $RELEASEVER == 7 ];then -    curl http://mirrors.163.com/.help/CentOS7-Base-163.repo > qf.repo -fi -yum clean all -yum check-update - -# install base rpm package -yum -y insall epel-release -yum -y install nc vim iftop iotop dstat tcpdump -yum -y install ipmitool bind-libs bind-utils -yum -y install libselinux-python ntpdate - -# update rpm package include kernel -yum -y update -rm -rf /etc/yum.repos.d/CentOS* - -# update ulimit configure -if [ $RELEASEVER == 6 ];then -    test -f /etc/security/limits.d/90-nproc.conf && rm -rf /etc/security/limits.d/90-nproc.conf && touch /etc/security/limits.d/90-nproc.conf -fi -if [ $RELEASEVER == 7 ];then -    test -f /etc/security/limits.d/20-nproc.conf && rm -rf /etc/security/limits.d/20-nproc.conf && touch /etc/security/limits.d/20-nproc.conf -fi - -> /etc/security/limits.conf -cat >> /etc/security/limits.conf < /dev/null 2>&1' > /var/spool/cron/root;chmod 600 /var/spool/cron/root -    fi -    /etc/init.d/crond restart -fi - -if [ $RELEASEVER == 7 ];then -    yum -y install chrony -    > /etc/chrony.conf -cat > /etc/chrony.conf << EOF -server pool.ntp.org iburst -stratumweight 0 -driftfile /var/lib/chrony/drift -rtcsync -makestep 10 3 -bindcmdaddress 127.0.0.1 -bindcmdaddress ::1 -keyfile /etc/chrony.keys -commandkey 1 -generatecommandkey -noclientlog -logchange 0.5 -logdir /var/log/chrony -EOF - - systemctl restart chronyd - systemctl enable chronyd -fi - -# clean iptables default rules -if [ $RELEASEVER == 6 ];then -    /sbin/iptables -F -    service iptables save -    chkconfig iptables off -fi -if [ $RELEASEVER == 7 ];then -    systemctl disable firewalld -fi - -# disable unused service -chkconfig auditd off - -# disable ipv6 -cd /etc/modprobe.d/ && touch ipv6.conf -> /etc/modprobe.d/ipv6.conf -cat >> /etc/modprobe.d/ipv6.conf << EOF -alias net-pf-10 off -alias ipv6 off -EOF - -# disable iptable nat moudule -cd /etc/modprobe.d/ && touch connectiontracking.conf -> /etc/modprobe.d/connectiontracking.conf -cat >> /etc/modprobe.d/connectiontracking.conf <> /etc/profile -fi - -# install dsnmasq and update configure -yum -y install dnsmasq -> /etc/dnsmasq.conf -cat >> /etc/dnsmasq.conf<< EOF -listen-address=127.0.0.1 -no-dhcp-interface=lo -log-queries -log-facility=/var/log/dnsmasq.log -all-servers -no-negcache -cache-size=1024 -dns-forward-max=512 -EOF - -if [ $RELEASEVER == 6 ];then -    /etc/init.d/dnsmasq restart -fi - -if [ $RELEASEVER == 7 ];then -    systemctl restart dnsmasq - systemctl enable dnsmasq -fi - -# update /etc/resolv.conf -> /etc/resolv.conf -cat >> /etc/resolv.conf<< EOF -options timeout:1 -nameserver 127.0.0.1 -nameserver 114.114.114.114 -EOF - -# update /etc/sysctl.conf -cat >> /etc/sysctl.conf<< EOF -net.ipv4.tcp_syncookies = 1 -kernel.core_uses_pid=1 -kernel.core_pattern=/tmp/core-%e-%p -fs.suid_dumpable=2 -net.ipv4.tcp_tw_reuse=1 -net.ipv4.tcp_tw_recycle=0 -net.ipv4.tcp_timestamps=1 -EOF -sysctl -p -``` - -6、LAMP环境部署 - -```shell -#!/bin/bash -cat <<-EOF -+-------------------------------------------------------------------------+ -| LAMP环境部署 V1.0 | -+-------------------------------------------------------------------------+ -| a. 部署Apache服务 | -| b. 部署php服务 | -| c. 部署Mysql服务 | -| d. 一键部署LAMP | -| q. 按q键退出程序 | -+-------------------------------------------------------------------------+ -EOF -# 安装Apache -install_Apache() -{ -systemctl stop firewalld -systemctl disable firewalld -setenforce 0 -sed -i '/^\bSELINUX\b/c SELINUX=disabled' /etc/selinux/config -mkdir /usr/local/apr &> /dev/null -mkdir /usr/local/apr-util &> /dev/null -mkdir /usr/local/apache &> /dev/null -cd /usr/local/src -echo "正在下载Apache服务,请稍等!!!" -wget http://archive.apache.org/dist/apr/apr-1.6.5.tar.gz &> /dev/null -wget http://archive.apache.org/dist/apr/apr-util-1.6.1.tar.gz &> /dev/null -wget http://mirrors.hust.edu.cn/apache/httpd/httpd-2.4.37.tar.gz &> /dev/null -if [ $? -eq 0 ] -then -echo "download success" -else -echo "download failed" -exit -fi -tar xf apr-1.6.5.tar.gz -tar xf apr-util-1.6.1.tar.gz -tar xf httpd-2.4.37.tar.gz -echo "正在安装所需的依赖包" -yum -y install gcc gcc-c++ openssl openssl-devel expat-devel &> /dev/null -if [ $? -eq 0 ] -then -echo "依赖包安装成功" -else -echo "依赖包安装失败" -exit -fi -cd /usr/local/src/apr-1.6.5/ -echo "正在配置和编译安装apr,请喝口水稍等!!!" -./configure --prefix=/usr/local/apr/ &> /dev/null -make &> /dev/null && make install &>/dev/null -if [ $? -eq 0 ] -then -echo "apr installed" -else -echo "apr installed failed" -exit -fi -cd /usr/local/src/apr-util-1.6.1/ -./configure --prefix=/usr/local/apr-util --with-apr=/usr/local/apr/ &> /dev/null -make &> /dev/null && make install &> /dev/null -if [ $? -eq 0 ] -then -echo "apr-util installed" -else -echo "apr-util installed failed" -exit -fi -cd /usr/local/src/httpd-2.4.37/ -echo "正在配置Apache" -./configure --prefix=/usr/local/apache/ --with-apr=/usr/local/apr/ --with-apr-util=/usr/local/apr-util/ --enable-so --enable-ssl--enable-deflate=shared --enable-expires=shared --enable-rewrite=shared --enable-static-support &> /dev/null -make &> /dev/null && make install &> /dev/null -if [ $? -eq 0 ] -then -echo "Apache installed" -else -echo "Apache installed failed" -exit -fi -cd /usr/local/apache/bin/ -echo ServerName www.fangxi.com >> /usr/local/apache/conf/httpd.conf -./apachectl start -if [ $? -eq 0 ] -then -echo "Apache安装成功并启动" -else -echo "Apache启动失败" -exit -fi -} - -#安装php -install_php() -{ -echo "正在安装php服务" -yum -y install php php-cli php-curl php-fpm php-intl php-mcryp php-mysql php-gd php-mbstring php-xml php-dom &> /dev/null -if [ $? -eq 0 ] -then -echo "php安装成功" -else -echo "php安装失败" -exit -fi -systemctl start php-fpm &> /dev/null -if [ $? -eq 0 ] -then -echo "php安装成功" -else -echo "php安装失败" -exit -fi - -} -#编译安装Mysql -install_mysql() -{ -echo "开始安装mysql" -echo "正在准备编译环境,wait a minute" -yum -y install ncurses ncurses-devel openssl-devel bison gcc gcc-c++ make cmake &> /dev/null -if [ $? -eq 0 ] -then -echo "编译环境已准备好" -else -echo "编译环境准备失败" -exit -fi -echo "正在下载源码包----请稍稍等一下" -wget http://ftp.ntu.edu.tw/MySQL/Downloads/MySQL-5.7/mysql-boost-5.7.26.tar.gz -groupadd mysql -useradd -r -g mysql -s /bin/nologin mysql -tar xf mysql-boost-5.7.26.tar.gz -cd mysql-5.7.26/ -echo "正在配置中,请再喝口水,小憩一下" -cmake . \ --DWITH_BOOST=boost/boost_1_59_0/ \ --DCMAKE_INSTALL_PREFIX=/usr/local/mysql \ --DSYSCONFDIR=/etc \ --DMYSQL_DATADIR=/usr/local/mysql/data \ --DINSTALL_MANDIR=/usr/share/man \ --DMYSQL_TCP_PORT=3306 \ --DMYSQL_UNIX_ADDR=/tmp/mysql.sock \ --DDEFAULT_CHARSET=utf8 \ --DEXTRA_CHARSETS=all \ --DDEFAULT_COLLATION=utf8_general_ci \ --DWITH_READLINE=1 \ --DWITH_SSL=system \ --DWITH_EMBEDDED_SERVER=1 \ --DENABLED_LOCAL_INFILE=1 \ --DWITH_INNOBASE_STORAGE_ENGINE=1 &> /dev/null -if [ $? -eq 0 ] -then -echo "mysql配置成功" -else -echo "mysql配置失败" -exit -fi -echo "----------正在安装编译安装Mysql请稍等-----------" -make &> /dev/null && make install /dev/null -if [ $? -eq 0 ] -then -echo "mysql编译安装成功" -else -echo "mysql编译安装失败" -exit -fi -echo [mysqld] > /etc/my.cnf -echo basedir=/usr/local/mysql >> /etc/my.cnf -echo datadir=/usr/local/mysql/data >> /etc/my.cnf -echo "mysql配置文件successed" -cd /usr/local/mysql/ -mkdir mysql-files -chown -R mysql.mysql /usr/local/mysql -echo "-------------正在初始化Mysql请稍等--------------" -/usr/local/mysql/bin/mysqld --initialize --user=mysql --basedir=/usr/local/mysql --datadir=/usr/local/mysql/data &> mima.txt -mima=awk '/password/ {print $NF}' mima.txt -echo "初始密码为:$mima" -if [ $? -eq 0 ] -then -echo "mysql初始化成功" -else -echo "mysql初始化失败" -exit -fi -bin/mysql_ssl_rsa_setup --datadir=/usr/local/mysql/data -#给数据库加密 -cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld -chkconfig --add mysqld -chkconfig mysqld on -#添加到开机启动项 -systemctl start mysqld -if [ $? -eq 0 ] -then -echo "mysql启动成功" -else -echo "mysql启动失败" -exit -fi -echo "export PATH=$PATH:/usr/local/mysql/bin" >> /etc/profile -source /etc/profile -echo "----------修改数据库初始密码----------" -read -p "请输入你要设置的数据库密码" new_mima -mysqladmin -uroot -p${mima} password "$new_mima" -if [ $? -eq 0 ] -then -echo "mysql初始密码修改成功,mysql部署完成" -else -echo "mysql初始密码修改失败" -exit -fi - -} -while : -do -read -p "请输入你要选择的参数: " var -case $var in -a) -install_Apache -;; -b) -install_php -;; -c) -install_mysql -;; -d) -install_Apache -install_php -install_mysql -;; -q) -exit -;; -*) -printf "请按照上方提供的选项输入!!!\n" -;; -esac -done -``` - +# Shell 流编辑器 AWK + +## 一、AWK 简介 + +AWK 是一种编程语言,用于在linux/unix下对文本和数据进行处理。数据可以来自标准输入、一个或多个文件,或其它命令的输出。它支持用户自定义函数和动态正则表达式等先进功能,是linux/unix下的一个强大编程工具。它在命令行中使用,但更多是作为脚本来使用。 + +AWK 逐行扫描文件,从第一行到最后一行,寻找匹配的特定模式的行,并在这些行上进行你想要的操作。如果没有指定处理动作,则把匹配的行显示到标准输出(屏幕),如果没有指定模式,则所有被操作所指定的行都被处理。awk分别代表其作者姓氏的第一个字母。因为它的作者是三个人,分别是Alfred Aho、Brian Kernighan、Peter Weinberger。gawk是awk的GNU版本,它提供了Bell实验室和GNU的一些扩展。 + +## 二、AWK 语法 + +```shell +awk [-F field-separator] 'commands' input-file(s) +awk [选项参数] 'commands' var=value file(s) +``` + +- commands 是真正 AWK 命令,[-F域分隔符]是可选的。 input-file(s) 是待处理的文件 + +- AWK 中,文件的每一行中,由域分隔符分开的每一项称为一个域。通常,在不指名-F域分隔符的情况下,默认的域分隔符是空格。 + +```shell +# awk -f awk-script-file input-file(s) +# awk [选项参数] -f scriptfile var=value file(s) +``` + +- -f 选项加载 awk-script-file 中的 awk 脚本,input-file(s) 是待处理的文件。 + +- 将所有的awk命令插入一个脚本文件,使用awk命令解释器作为脚本的首行,相当于shell脚本首行的:#!/bin/sh 可以换成:#!/bin/awk。通过执行脚本来调用 + +## 三、AWK 工作原理 + +AWK 工作流程可分为三个部分: + +- 读输入文件之前执行的代码段(由BEGIN关键字标识)。 +- 主循环执行输入文件的代码段。 +- 读输入文件之后的代码段(由END关键字标识)。 + +### 1、AWK 命令结构 + +```shell +awk 'BEGIN{ commands } pattern{ commands } END{ commands }' +``` + +下图是 AWK 的工作流程 + +![img](https://oss-wxin-resource.oss-cn-beijing.aliyuncs.com/%E5%9B%BE%E7%89%87/Awk/1.png) + +- 通过关键字 BEGIN 执行 BEGIN 块的内容,即 BEGIN 后花括号 **{}** 的内容。 +- 完成 BEGIN 块的执行,开始执行body块。 +- 读入有 **\n** 换行符分割的记录。 +- 将记录按指定的域分隔符划分域,填充域,**$0** 则表示所有域(即一行内容),**$1** 表示第一个域,**$n** 表示第 n 个域。 +- 依次执行各 BODY 块,pattern 部分匹配该行内容成功后,才会执行 awk-commands 的内容。 +- 循环读取并执行各行直到文件结束,完成body块执行。 +- 开始 END 块执行,END 块可以输出最终结果。 + +### 2、开始块(BEGIN) + +开始块的语法格式如下: + +```shell +BEGIN {awk-commands} +``` + +开始块就是在程序启动的时候执行的代码部分,并且它在整个过程中只执行一次。 + +一般情况下,我们可以在开始块中初始化一些变量。 + +BEGIN 是 AWK 的关键字,因此它必须是大写的。 + +**注意:**开始块部分是可选的,你的程序可以没有开始块部分。 + +### 3、主体块(BODY) + +主体部分的语法格式如下: + +```sh +/pattern/ {awk-commands} +``` + +对于每一个输入的行都会执行一次主体部分的命令。 + +默认情况下,对于输入的每一行,AWK 都会执行命令。但是,我们可以将其限定在指定的模式中。 + +**注意**:在主体块部分没有关键字存在。 + +### 4、结束块(END) + +结束块的语法格式如下: + +```shell +END {awk-commands} +``` + +结束块是在程序结束时执行的代码。 END 也是 AWK 的关键字,它也必须大写。 与开始块相似,结束块也是可选的。 + +### 5、实例 + +先创建一个名为 marks.txt 的文件。其中包括序列号、学生名字、课程名称与所得分数。 + +```shell +1) 张三 语文 80 +2) 李四 数学 90 +3) 王五 英语 87 +``` + +接下来,我们将使用 AWK 脚本来显示输出文件中的内容,同时输出表头信息。 + +```shell +[root@qfedu.com ~]# awk 'BEGIN{printf "序号\t名字\t课程\t分数\n"} {print}' marks.txt +``` + +执行以上命令,输出结果如下: + +```shell +序号 名字 课程 分数 +1) 张三 语文 80 +2) 李四 数学 90 +3) 王五 英语 87 +``` + +程序开始执行时,AWK 在开始块中输出表头信息。在主体块中,AWK 每读入一行就将读入的内容输出至标准输出流中,一直到整个文件被全部读入为止。 + +## 四、AWK 选项 + +- -F fs or --field-separator fs + 指定输入文件折分隔符,fs是一个字符串或者是一个正则表达式,如-F:。 +- -v var=value or --asign var=value + 赋值一个用户定义变量。 +- -f scripfile or --file scriptfile + 从脚本文件中读取awk命令。 +- -mf nnn and -mr nnn + 对nnn值设置内在限制,-mf选项限制分配给nnn的最大块数目;-mr选项限制记录的最大数目。这两个功能是Bell实验室版awk的扩展功能,在标准awk中不适用。 +- -W compact or --compat, -W traditional or --traditional + 在兼容模式下运行awk。所以gawk的行为和标准的awk完全一样,所有的awk扩展都被忽略。 +- -W copyleft or --copyleft, -W copyright or --copyright + 打印简短的版权信息。 +- -W help or --help, -W usage or --usage + 打印全部awk选项和每个选项的简短说明。 +- -W lint or --lint + 打印不能向传统unix平台移植的结构的警告。 +- -W lint-old or --lint-old + 打印关于不能向传统unix平台移植的结构的警告。 +- -W posix + 打开兼容模式。但有以下限制,不识别:/x、函数关键字、func、换码序列以及当fs是一个空格时,将新行作为一个域分隔符;操作符**和**=不能代替^和^=;fflush无效。 +- -W re-interval or --re-inerval + 允许间隔正则表达式的使用,参考(grep中的Posix字符类),如括号表达式[[:alpha:]]。 +- -W source program-text or --source program-text + 使用program-text作为源代码,可与-f命令混用。 +- -W version or --version + 打印bug报告信息的版本。 + +## 五、AWK 基本用法 + +1、创建 log.txt 文件 + +```shell +[root@qfedu.com ~]# cat log.txt +2 this is a test +3 Are you like awk +This's a test +10 There are orange,apple,mongo +``` + +2、行匹配语句(默认分隔符) + +```sh +awk '{[pattern] action}' {filenames} # 行匹配语句 awk '' 只能用单引号 +``` + +```shell +# 每行按空格或TAB分割,输出文本中的1、4项 +[root@qfedu.com ~]# awk '{print $1,$4}' log.txt +2 a +3 like +This's +10 orange,apple,mongo + +# 格式化输出 +[root@qfedu.com ~]# awk '{printf "%-8s %-10s\n",$1,$4}' log.txt +2 a +3 like +This's +10 orange,apple,mongo +``` + +3、指定分割字符 + +```shell +awk -F #-F相当于内置变量FS, 指定分割字符 +``` + +```shell +# 使用","分割 +[root@qfedu.com ~]# awk -F, '{print $1,$2}' log.txt +2 this is a test +3 Are you like awk +This's a test +10 There are orange apple + +# 或者使用内建变量 +[root@qfedu.com ~]# awk 'BEGIN{FS=","} {print $1,$2}' log.txt +2 this is a test +3 Are you like awk +This's a test +10 There are orange apple + +# 使用多个分隔符.先使用空格分割,然后对分割结果再使用","分割 +[root@qfedu.com ~]# awk -F '[ ,]' '{print $1,$2,$5}' log.txt +2 this test +3 Are awk +This's a +10 There apple +``` + +3、设置变量 + +```shell +awk -v #设置变量 +``` + +```shell +[root@qfedu.com ~]# awk -va=1 '{print $1,$1+a}' log.txt +2 3 +3 4 +This's 1 +10 11 + +[root@qfedu.com ~]# awk -va=1 -vb=s '{print $1,$1+a,$1b}' log.txt +2 3 2s +3 4 3s +This's 1 This'ss +10 11 10s +``` + +4、正则匹配 + +~ 表示模式开始。// 中是模式。 + +```shell +[root@qfedu.com ~]# awk '$1 ~ /bin/ {print $1,$4}' /etc/passwd +[root@qfedu.com ~]# awk -F: '$1 ~ /^alice/' /etc/passwd + +# 输出包含"root" 的行 +[root@qfedu.com ~]# awk '/root/ ' /etc/passwd +root:x:0:0:root:/root:/bin/bash +operator:x:11:0:operator:/root:/sbin/nologin + +# 匹配记录(整行): +[root@qfedu.com ~]# awk '/^alice/' /etc/passwd +[root@qfedu.com ~]# awk '$0 ~ /^alice/' /etc/passwd +[root@qfedu.com ~]# awk '!/alice/' passwd +[root@qfedu.com ~]# awk '$0 !~ /^alice/' /etc/passwd +``` + +5、忽略大小写 + +```shell +[root@qfedu.com ~]# awk 'BEGIN{IGNORECASE=1} /bin/' /etc/passwd +``` + +6、模式取反 + +```shell +[root@qfedu.com ~]# awk '$1 !~ /bin/ {print $1,$4}' /etc/passwd +[root@qfedu.com ~]# awk -F: '$NF !~ /bash$/' /etc/passwd +``` + +7、使用 AWK 脚本 + +```shell +awk -f {awk脚本} {文件名} +``` + +```shell +[root@qfedu.com ~]# awk -f cal.awk log.txt +``` + +## 六、格式化打印 + +- print 和 printf 都是打印输出的,不过两者用法和显示上有些不同而已。 + + +```shell +print 格式:print item1,item2, ... +printf格式:printf “FORMAT ”,item1,item2, ... +``` + +- 逗号为分隔符时,显示的是空格; + +- 分隔符分隔的字段(域)标记称为域标识,用$0,$1,$2,...,$n表示,其中$0 为所有域,$1就是表示第一个字段(域),以此类推; + +- 输出的各item可以字符串,也可以是数值,当前记录的字段,变量或awk 的表达式等; + +- 如果省略了item ,相当于print $0 + +- 对于printf来说,其中格式化字符串包括两部分内容: 一部分是正常字符,这些字符将按原样输出; 另一部分是格式化规定字符, 以 **%** 开始, 后跟一个或几个规定字符,用来确定输出内容格式,必须指定 FORMAT,即必须指出后面每个itemsN 的输出格式,**printf** 时默认是不会换行的,而 **print** 函数默认会在每行后面加上 **\n** 换行符 + +| **格式符** | **说明** | +| :--------- | :----------------------------------------------------------- | +| %d | 十进制有符号整数 | +| %u | 十进制无符号整数 | +| %f | 浮点数 | +| %s | 字符串 | +| %c | 单个字符 | +| %p | 指针的值 | +| %e | 指数形式的浮点数 | +| %x | %X 无符号以十六进制表示的整数 | +| %o | 无符号以八进制表示的整数 | +| %g | 自动选择合适的表示法 | +| %% | 显示%自身 | +| #[.#] | 第一个数字控制显示的宽度;第二个#表示小数点后精度,%3.1f | +| - | 左对齐(默认右对齐);%-15s,就是以左对齐方式显示15个字符长度 | +| + | 显示数值的正负符号 %+d | + +- 实例 + + +```sh +# print 函数 +[root@qfedu.com ~]# awk '{print "hello,awk"}' +[root@qfedu.com ~]# awk –F: '{print}' /etc/passwd +[root@qfedu.com ~]# awk –F: ‘{print “wang”}’ /etc/passwd +[root@qfedu.com ~]# awk –F: ‘{print $1}’ /etc/passwd +[root@qfedu.com ~]# awk –F: ‘{print $0}’ /etc/passwd +[root@qfedu.com ~]# awk –F: ‘{print $1”\t”$3}’ /etc/passwd +[root@qfedu.com ~]# date |awk '{print "Month: " $2 "\nYear: " $NF}' +[root@qfedu.com ~]# awk -F: '{print "username is: " $1 "\t uid is: " $3}' /etc/passwd +[root@qfedu.com ~]# awk -F: '{print "\tusername and uid: " $1,$3 "!"}' /etc/passwd + +# printf函数 +[root@qfedu.com ~]# tail –3 /etc/fstab |awk ‘{print $2,$4}’ +[root@qfedu.com ~]# awk -F: '{printf "%-15s %-10s %-15s\n", $1,$2,$3}' /etc/passwd +[root@qfedu.com ~]# awk -F: '{printf "|%-15s| %-10s| %-15s|\n", $1,$2,$3}' /etc/passwd +[root@qfedu.com ~]# awk -F: ‘{printf "%s",$1}’ /etc/passwd +[root@qfedu.com ~]# awk -F: ‘{printf "%s\n",$1}’ /etc/passwd +[root@qfedu.com ~]# awk -F: '{printf "%-20s %10d\n",$1,$3}' /etc/passwd +[root@qfedu.com ~]# awk -F: ‘{printf "Username: %s\n",$1}’ /etc/passwd +[root@qfedu.com ~]# awk -F: ‘{printf “Username: %s,UID:%d\n",$1,$3}’ /etc/passwd +[root@qfedu.com ~]# awk -F: ‘{printf "Username: %15s,UID:%d\n",$1,$3}’ /etc/passwd +[root@qfedu.com ~]# awk -F: ‘{printf "Username: %-15s,UID:%d\n",$1,$3}’ /etc/passwd +[root@qfedu.com ~]# lsmod | awk -v FS=" " 'BEGIN{printf "%s %26s %10s\n","Module","Size","Used by"}{printf "%-20s %13d %5s %s\n",$1,$2,$3,$4}' /proc/modules +``` + +## 七、AWK 运算符 + +| 运算符 | 描述 | +| :---------------------- | :------------------------------- | +| = += -= *= /= %= ^= **= | 赋值 | +| ?: | C条件表达式 | +| \|\| | 逻辑或 | +| && | 逻辑与 | +| ~ 和 !~ | 匹配正则表达式和不匹配正则表达式 | +| < <= > >= != == | 关系运算符 | +| 空格 | 连接 | +| + - | 加,减 | +| * / % | 乘,除与求余 | +| + - ! | 一元加,减和逻辑非 | +| ^ *** | 求幂 | +| ++ -- | 增加或减少,作为前缀或后缀 | +| $ | 字段引用 | +| in | 数组成员 | + +过滤第一列大于2的行 + +```shell +[root@qfedu.com ~]# awk '$1>2' log.txt +3 Are you like awk +This's a test +10 There are orange,apple,mongo +``` + +过滤第一列等于2的行 + +```shell +[root@qfedu.com ~]# awk '$1==2 {print $1,$3}' log.txt +2 is +``` + +过滤第一列大于2并且第二列等于'Are'的行 + +```shell +[root@qfedu.com ~]# awk '$1>2 && $2=="Are" {print $1,$2,$3}' log.txt +3 Are you +``` + +过滤练习 + +```shell +[root@qfedu.com ~]# awk -F: '$3 == 0' /etc/passwd +[root@qfedu.com ~]# awk -F: '$3 < 10' /etc/passwd +[root@qfedu.com ~]# awk -F: '$NF == "/bin/bash"' /etc/passwd +[root@qfedu.com ~]# awk -F: '$1 == "alice"' /etc/passwd +[root@qfedu.com ~]# awk -F: '$1 ~ /alic/ ' /etc/passwd +[root@qfedu.com ~]# awk -F: '$1 !~ /alic/ ' /etc/passwd +[root@qfedu.com ~]# df -P | grep '/' |awk '$4 > 25000' +``` + +## 八、AWK 变量 + +### 1、AWK 内置变量 + +| 变量 | 描述 | +| :---------- | :--------------------------------------------------------- | +| $n | 当前记录的第n个字段,字段间由FS分隔 | +| $0 | 完整的输入记录 | +| ARGC | 命令行参数的数目 | +| ARGIND | 命令行中当前文件的位置(从0开始算) | +| ARGV | 包含命令行参数的数组 | +| CONVFMT | 数字转换格式(默认值为%.6g)ENVIRON环境变量关联数组 | +| ERRNO | 最后一个系统错误的描述 | +| FIELDWIDTHS | 字段宽度列表(用空格键分隔) | +| FILENAME | 当前文件名 | +| FNR | 各文件分别计数的行号 | +| FS | 字段分隔符(默认是任何空格) | +| IGNORECASE | 如果为真,则进行忽略大小写的匹配 | +| NF | 一条记录的字段的数目 | +| NR | 已经读出的记录数,就是行号,从1开始 | +| OFMT | 数字的输出格式(默认值是%.6g) | +| OFS | 输出记录分隔符(输出换行符),输出时用指定的符号代替换行符 | +| ORS | 输出记录分隔符(默认值是一个换行符) | +| RLENGTH | 由match函数所匹配的字符串的长度 | +| RS | 记录分隔符(默认是一个换行符) | +| RSTART | 由match函数所匹配的字符串的第一个位置 | +| SUBSEP | 数组下标分隔符(默认值是/034) | + +```shell +[root@qfedu.com ~]# awk -F: '{print $0}' /etc/passwd # $0 +[root@qfedu.com ~]# awk -F: '{print NR, $0}' /etc/passwd /etc/hosts # NR +[root@qfedu.com ~]# awk -F: '{print FNR, $0}' /etc/passwd /etc/hosts # FNR +[root@qfedu.com ~]# awk -F: '{print $0,NF}' /etc/passwd # NF +[root@qfedu.com ~]# awk -F: '/alice/{print $1, $3}' /etc/passwd # FS +[root@qfedu.com ~]# awk -F'[ :\t]' '{print $1,$2,$3}' /etc/passwd +[root@qfedu.com ~]# awk 'BEGIN{FS=":"} {print $1,$3}' /etc/passwd +[root@qfedu.com ~]# awk -F: '/alice/{print $1,$2,$3,$4}' /etc/passwd # OFS +[root@qfedu.com ~]# awk 'BEGIN{FS=":"; OFS="+++"} /^root/{print $1,$2,$3,$4}' passwd +[root@qfedu.com ~]# awk -F: 'BEGIN{RS=" "} {print $0}' a.txt # RS +[root@qfedu.com ~]# awk -F: 'BEGIN{ORS=""} {print $0}' passwd # ORS +``` + +- 字段分隔符: FS OFS 默认空格或制表符 + +- 记录分隔符: RS ORS 默认换行符 + +```shell +# ORS 默认输出一条记录应该回车,加了一个空格 +[root@qfedu.com ~]# awk 'BEGIN{ORS=" "} {print $0}' /etc/passwd # 将文件每一行合并为一行 + +[root@qfedu.com ~]# head -1 /etc/passwd > passwd1 +[root@qfedu.com ~]# cat passwd1 +root:x:0:0:root:/root:/bin/bash +[root@qfedu.com ~]# awk 'BEGIN{RS=":"} {print $0}' passwd1 +root +x +0 +0 +root +/root +/bin/bash + +[root@qfedu.com ~]# awk 'BEGIN{RS=":"} {print $0}' passwd1 |grep -v '^$' > passwd2 + +# 输出顺序号 NR, 匹配文本行号 +[root@localhost ~]# awk '{print NR,FNR,$1,$2,$3}' /etc/passwd +1 1 root:x:0:0:root:/root:/bin/bash +2 2 bin:x:1:1:bin:/bin:/sbin/nologin +3 3 daemon:x:2:2:daemon:/sbin:/sbin/nologin +4 4 adm:x:3:4:adm:/var/adm:/sbin/nologin +5 5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin + +# 指定输出分割符 +[root@localhost ~]# awk '{print $1,$2,$5}' OFS=" $ " /etc/passwd +root:x:0:0:root:/root:/bin/bash $ $ +bin:x:1:1:bin:/bin:/sbin/nologin $ $ +daemon:x:2:2:daemon:/sbin:/sbin/nologin $ $ +adm:x:3:4:adm:/var/adm:/sbin/nologin $ $ +lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin $ $ +``` + +### 2、AWK 自定义变量(区分字符大小写) + +```shell +在'{...}'前,需要用-v var=value:awk -v var=value '{...}' +在program 中直接定义:awk '{var=vlue}' +``` + +### 3、AWK 使用外部变量 + +1、在双引号的情况下使用 + +```shell +[root@qfedu.com ~]# var="bash" +[root@qfedu.com ~]# echo "unix script" |awk "gsub(/unix/,\"$var\")" +bash script +``` + +2、在单引号的情况下使用 + +```shell +[root@qfedu.com ~]# var="bash" +[root@qfedu.com ~]# echo "unix script" |awk 'gsub(/unix/,"'"$var"'")' +bash script + +[root@qfedu.com ~]# df -h +Filesystem Size Used Avail Use% Mounted on +/dev/mapper/cl-root 2.8T 246G 2.5T 9% / +tmpfs 24G 20K 24G 1% /dev/shm +/dev/sda2 1014M 194M 821M 20% /boot + +[root@qfedu.com ~]# df -h |awk '{ if(int($5)>5){print $6":"$5} }' +/:9% +/boot:20% + +[root@qfedu.com ~]# i=10 +[root@qfedu.com ~]# df -h |awk '{ if(int($5)>'''$i'''){print $6":"$5} }' +/boot:20% +``` + +3、AWK 参数-v(建议) + +```shell +[root@qfedu.com ~]# echo "unix script" |awk -v var="bash" 'gsub(/unix/,var)' +bash script + +[root@qfedu.com ~]# awk -v user=root -F: '$1 == user' /etc/passwd +root:x:0:0:root:/root:/bin/bash +``` + +4、AWK 练习 + +```shell +[root@qfedu.com ~]# awk -F ':' '$3=="0"' /etc/passwd # 以冒号为分隔符,打印第三段是文本0的行,双引号代表字符,没有双引号代表数字 +[root@qfedu.com ~]# awk -F ':' '$3>="500"' /etc/passwd # 以冒号为分隔符,打印第三段大于等于字符串500的行 +[root@qfedu.com ~]# awk -F ':' '$3>=500' /etc/passwd # 以冒号为分隔符,打印第三段大于等于数字500的行 +[root@qfedu.com ~]# awk -F ':' '$7!="/sbin/nologin"' /etc/passwd # 以冒号为分隔符,打印第七段不为/sbin/nologin的行 +[root@qfedu.com ~]# awk -F ':' '$3<$4' /etc/passwd # 以冒号为分隔符,打印第三段小于第四段的行 +[root@qfedu.com ~]# awk -F ':' '$3>"5" && $3<"7"' /etc/passwd # 以冒号为分隔符,打印第三段大于字符5且第三段小于字符7的行 +[root@qfedu.com ~]# awk -F ':' '$3>1000 || $7=="/bin/bash"' /etc/passwd # 以冒号为分隔符,打印第三段大于1000或者第七段等于/bin/bash的行 +[root@qfedu.com ~]# head -5 /etc/passwd |awk -F ':' '{OFS="#"} {print $1,$3,$4}‘ # 以冒号为分隔符,打印每行第1、3、4段,并以井号间隔 +[root@qfedu.com ~]# awk -F ':' '{OFS="#"} {if ($3>1000) {print $1,$2,$3,$4}}' /etc/passwd # 以冒号为分隔符,如果第三段大于1000则打印第1、3、4段,并以井号间隔 +[root@qfedu.com ~]# head -n3 /etc/passwd | awk -F ':' '{print NF}‘ # 以冒号为分隔符,逐行打印该行列数 +[root@qfedu.com ~]# head -n3 /etc/passwd | awk -F ':' '{print NR}‘ # 以冒号为分隔符,逐行打印该行行数 +[root@qfedu.com ~]# awk 'NR>40' /etc/passwd # 打印行数大于40的行 +[root@qfedu.com ~]# awk -F ':' 'NR<20 && $1 ~ /roo/' /etc/passwd # 打印行数小于20并且第一段包含roo的行 +[root@qfedu.com ~]# head -n 3 /etc/passwd |awk -F ':' '$1="root"‘ # 以冒号为分隔符,给第一段赋值root,然后打印每一行 +[root@qfedu.com ~]# awk -F ':' '{(tot=tot+$3)}; END {print tot}' /etc/passwd # 逐行做完tot=tot+3的运算,最后打印出tot的值 +[root@qfedu.com ~]# awk -F ':' '{if ($1=="root") {print $0}}' /etc/passwd # 如果第一段是root,打印该行 + +[root@qfedu.com ~]# awk -v FS=':' '{print $1,FS,$3}’ /etc/passwd +[root@qfedu.com ~]# awk –F: '{print $1,$3,$7}’ /etc/passwd +[root@qfedu.com ~]# awk -v FS=‘:’ -v OFS=‘:’ '{print $1,$3,$7}’ /etc/passwd +[root@qfedu.com ~]# awk -v RS=' ' ‘{print }’ /etc/passwd +[root@qfedu.com ~]# awk -v RS="[[:space:]/=]" '{print }' /etc/fstab |sort +[root@qfedu.com ~]# awk -v RS=' ' -v ORS='###'‘{print }’ /etc/passwd +[root@qfedu.com ~]# awk -F: ‘{print NF}’ /etc/fstab, 引用内置变量不用$ +[root@qfedu.com ~]# awk -F: '{print $(NF-1)}' /etc/passwd +[root@qfedu.com ~]# awk '{print NR}' /etc/fstab ; awk 'END{print NR}' /etc/fstab +[root@qfedu.com ~]# awk '{print FNR}' /etc/fstab /etc/inittab +[root@qfedu.com ~]# awk '{print FNR}' /etc/fstab /etc/inittab +[root@qfedu.com ~]# awk '{print FILENAME}’ /etc/fstab +[root@qfedu.com ~]# awk '{print ARGC}’ /etc/fstab /etc/inittab +[root@qfedu.com ~]# awk ‘BEGIN {print ARGC}’ /etc/fstab /etc/inittab +[root@qfedu.com ~]# awk ‘BEGIN {print ARGV[0]}’ /etc/fstab /etc/inittab +[root@qfedu.com ~]# awk ‘BEGIN {print ARGV[1]}’ /etc/fstab /etc/inittab +[root@qfedu.com ~]# awk -v test='hello gawk' '{print test}' /etc/fstab +[root@qfedu.com ~]# awk -v test='hello gawk' 'BEGIN{print test}' +[root@qfedu.com ~]# awk 'BEGIN{test="hello,gawk";print test}' +[root@qfedu.com ~]# awk –F:‘{sex=“male”;print $1,sex,age;age=18}’ /etc/passwd +[root@qfedu.com ~]# awk -F: '{sex="male";age=18;print $1,sex,age}' /etc/passwd +[root@qfedu.com ~]# echo "{print script,\$1,\$2}" > awkscript +[root@qfedu.com ~]# awk -F: -f awkscript script=“awk” /etc/passwd +``` + +## 九、AWK 脚本 + +### 1、AWK 脚本定义格式 + +```shell +格式1: +BEGIN{} pattern{} END{} + +格式2: +#!/bin/awk -f +#add 'x' right +BEGIN{} pattern{} END{} +``` + +关于awk 脚本,需要注意两个关键词BEGIN和END。 + +- BEGIN{ 这里面放的是执行前的语句 } +- END {这里面放的是处理完所有的行后要执行的语句 } +- {这里面放的是处理每一行时要执行的语句} + +- 格式1假设为f1.awk文件,格式2假设为f2.awk文件 + +```shell +awk [-v var=value] f1.awk [file] +f2.awk [-v var=value] [var1=value1] [file] +``` + +- awk [-v var=value] f1.awk [file],把处理阶段放到一个文件而已,展开后就是普通的awk语句。 + +- f2.awk [-v var=value] [var1=value1] [file] 中 [-v var=value] 是在BEGIN之前设置的变量值,[var1=value1]是在BEGIN过程之后进行的,也就是说直到首行输入完成后,这个变量才可用。 + +### 2、AWK 脚本练习 + +#### 1、AWK 脚本实例1 + +1、创建一个文件(学生成绩表) + +```shell +[root@qfedu.com ~]# cat score.txt +Marry 2143 78 84 77 +Jack 2321 66 78 45 +Tom 2122 48 77 71 +Mike 2537 87 97 95 +Bob 2415 40 57 62 +``` + +2、定义 awk 脚本 + +```shell +[root@qfedu.com ~]# cat cal.awk +#!/bin/awk -f +#运行前 +BEGIN { + math = 0 + english = 0 + computer = 0 + + printf "NAME NO. MATH ENGLISH COMPUTER TOTAL\n" + printf "---------------------------------------------\n" +} +#运行中 +{ + math+=$3 + english+=$4 + computer+=$5 + printf "%-6s %-6s %4d %8d %8d %8d\n", $1, $2, $3,$4,$5, $3+$4+$5 +} +#运行后 +END { + printf "---------------------------------------------\n" + printf " TOTAL:%10d %8d %8d \n", math, english, computer + printf "AVERAGE:%10.2f %8.2f %8.2f\n", math/NR, english/NR, computer/NR +} + +[root@qfedu.com ~]# awk -f cal.awk score.txt +NAME NO. MATH ENGLISH COMPUTER TOTAL +--------------------------------------------- +Marry 2143 78 84 77 239 +Jack 2321 66 78 45 189 +Tom 2122 48 77 71 196 +Mike 2537 87 97 95 279 +Bob 2415 40 57 62 159 +--------------------------------------------- + TOTAL: 319 393 350 +AVERAGE: 63.80 78.60 70.00 +``` + +2、AWK 脚本实例2 + +```shell +cat f1.awk + {if($3>=1000)print $1,$3} +awk -F: -f f1.awk /etc/passwd + +cat f2.awk + #!/bin/awk –f + # this is a awk script + {if($3>=1000)print $1,$3} + # chmod +x f2.awk +f2.awk –F: /etc/passwd + +cat test.awk + #!/bin/awk –f + {if($3 >=min && $3<=max)print $1,$3} + #chmod +x test.awk +test.awk -F: min=100 max=200 /etc/passwd +``` + +## 十、AWK 流程控制 + +### 1、AWK 条件语句 + +#### 1、IF 语句 + +##### 1、IF 条件语句语法格式 + +```shell +if (condition) + action +``` + +使用花括号语法格式 + +```shell +if (condition) +{ + action1; + action2; + ... +} + +{if(表达式){语句1;语句2;...}} +``` + +##### 2、IF 语句实例 + +###### 1、判断数字是奇数还是偶数 + +```shell +[root@qfedu.com ~]# awk 'BEGIN {num = 10; if (num % 2 == 0) printf "%d 是偶数\n", num }' +10 是偶数 +``` + +###### 2、判断 root 是不是 administrator + +```shell +[root@qfedu.com ~]# awk -F: '{if($3==0) {print $1 " is administrator."}}' /etc/passwd +root is administrator. +``` + +###### 3、 统计系统用户数 + +```shell +[root@qfedu.com ~]# awk -F: '{if($3>0 && $3<1000){count++;}} END{print count}' /etc/passwd   +20 +``` + +#### 2、IF - ELSE 语句 + +##### 1、IF - ELSE 条件语句语法格式 + +```shell +if (condition) + action1 +else + action2 +``` + +使用花括号语法格式 + +```shell +{if (condition) +{ + action1; + action2; + ... +} +else +{ + action1; + action2; + ... +}} + +{if(表达式){语句1;语句2;...}else{语句1;语句2;...}} +``` + +##### 2、IF - ELSE 语句实例 + +###### 1、判断数字是奇数还是偶数 + +```shell +[root@qfedu.com ~]# awk 'BEGIN { + num = 11; + if (num % 2 == 0) printf "%d 是偶数\n", num; + else printf "%d 是奇数\n", num +}' + +11 是奇数 +``` + +###### 2、判断用户为root就打印用户名否则打印shell类型 + +```shell +[root@qfedu.com ~]# awk -F: '{if($3==0){print $1} else {print $7}}' /etc/passwd +root +/sbin/nologin +/sbin/nologin +/sbin/nologin +/sbin/nologin +/bin/sync +/sbin/shutdown +``` + +###### 3、统计管理员数量和系统用户数量 + +```shell +[root@qfedu.com ~]# awk -F: '{if($3==0){count++} else{i++}} END{print "管理员个数: "count ; print "系统用户数: "i}' /etc/passwd +管理员个数: 1 +系统用户数: 20 +``` + +#### 3、IF - ELSE - IF 语句 + +##### 1、IF - ELSE - IF条件语句语法格式 + +```shell +{if (condition1) +{ + action1; + action2; + ... +} +else if (condition2) +{ + action1; + action2; + ... +} +else if (condition3) +{ + action1; + action2; + ... +} +else +{ + action1; + action2; + ... +}} + +{if(表达式1){语句1;语句2;...}else if(表达式2){语句1;语句2;...}else if(表达式3){语句1;语句2;...}else{语句1;语句2;...}} +``` + +##### 2、IF - ELSE - IF 语句实例 + +###### 1、多级判断结果 + +```shell +[root@qfedu.com ~]# awk 'BEGIN { +a=30; +if (a==10) + print "a = 10"; +else if (a == 20) + print "a = 20"; +else if (a == 30) + print "a = 30"; +}' + +a = 30 +``` + +###### 2、统计管理员,系统,普通用户数量 + +```shell +[root@qfedu.com ~]# awk -F: '{if($3==0){i++} else if($3>999){k++} else{j++}} END{print i; print k; print j}' /etc/passwd +1 + +20 + +[root@qfedu.com ~]# awk -F: '{if($3==0){i++} else if($3>999){k++} else{j++}} END{print "管理员个数: "i; print "普通用个数: "k; print "系统用户: "j}' /etc/passwd +管理员个数: 1 +普通用个数: +系统用户: 20 +``` + +### 2、AWK 循环 + +#### 1、For 循环 + +##### 1、For 循环的语法 + +```shell +for(variable addignment; condition; iteration peocess) +{ + statement1 + statement2 + ... +} +``` + +for 语句首先执行初始化动作( initialisation ),然后再检查条件( condition )。如果条件为真,则执行动作( action ),然后执行递增( increment )或者递减( decrement )操作。只要条件为 true 循环就会一直执行。每次循环结束都会进条件检查,若条件为 false 则结束循环。 + +##### 2、For 循环实例 + +###### 1、For 循环输出数字 1 至 5 + +```shell +[root@qfedu.com ~]# awk 'BEGIN { for (i = 1; i <= 5; ++i) print i }' +1 +2 +3 +4 +5 +``` + +###### 2、For 循环输出数字 1 至 9 的奇数之和 + +```shell +[root@qfedu.com ~]# echo "hello" | awk ' +{ + total = 0 + for(i=1; i<10; i++) + { + if(i % 2 == 0) + { + continue + } + total = total + i + } + print "total=", total +}' +``` + +###### 3、将每行打印10次 + +```shell +[root@qfedu.com ~]# awk -F: '{ for(i=1;i<=10;i++) {print $0} }' /etc/passwd +root:x:0:0:root:/root:/bin/bash +root:x:0:0:root:/root:/bin/bash +root:x:0:0:root:/root:/bin/bash +root:x:0:0:root:/root:/bin/bash +root:x:0:0:root:/root:/bin/bash +root:x:0:0:root:/root:/bin/bash +root:x:0:0:root:/root:/bin/bash +root:x:0:0:root:/root:/bin/bash +root:x:0:0:root:/root:/bin/bash +root:x:0:0:root:/root:/bin/bash +``` + +###### 4、分别打印每行的每列 + +```shell +[root@qfedu.com ~]# awk -F: '{ for(i=1;i<=NF;i++) {print $i} }' /etc/passwd +root +x +0 +0 +root +/root +/bin/bash +bin +x +1 +1 +bin +/bin +/sbin/nologin +``` + +#### 2、While 循环 + +##### 1、While 循环的语法 + +```shell +while(condition) +{ + statement1 + statement2 + ... +} +``` + +While 循环首先检查条件 condition 是否为 true ,若条件为 true 则执行动作 action。此过程一直重复直到条件 condition 为 flase 才停止。 + +##### 2、While 循环实例 + +###### 1、While 循环输出数字 1 到 5 + +```shell +[root@qfedu.com ~]# awk 'BEGIN {i = 1; while (i < 6) { print i; ++i } }' +1 +2 +3 +4 +5 + +[root@qfedu.com ~]# awk 'BEGIN{ i=1; while(i<=5){print i; i++} }' +1 +2 +3 +4 +5 +``` + +###### 2、While 循环输出数字 1 至 9 的奇数之和 + +```shell +[root@qfedu.com ~]# echo "hello" | awk ' +{ + total = 0 + i = 1 + while(i < 10) + { + if(i % 2 == 0) + { + i++ + continue + } + total = total + i + i++ + } + print "total=", total +}' +``` + +###### 3、打印第一行的前七列 + +```shell +[root@qfedu.com ~]# awk -F: '/^root/{i=1; while(i<=7){print $i; i++}}' /etc/passwd +root +x +0 +0 +root +/root +/bin/bash +``` + +###### 4、分别打印每行的每列 + +```shell +[root@qfedu.com ~]# awk '{i=1; while(i<=NF){print $i; i++}}' /etc/hosts +127.0.0.1 +localhost +localhost.localdomain +localhost4 +localhost4.localdomain4 +::1 +localhost +localhost.localdomain +localhost6 +localhost6.localdomain6 +``` + +###### 5、将每行打印10次 + +```shell +[root@qfedu.com ~]# awk -F: '{i=1; while(i<=10) {print $0; i++}}' /etc/passwd +root:x:0:0:root:/root:/bin/bash +root:x:0:0:root:/root:/bin/bash +root:x:0:0:root:/root:/bin/bash +root:x:0:0:root:/root:/bin/bash +root:x:0:0:root:/root:/bin/bash +root:x:0:0:root:/root:/bin/bash +root:x:0:0:root:/root:/bin/bash +root:x:0:0:root:/root:/bin/bash +root:x:0:0:root:/root:/bin/bash +root:x:0:0:root:/root:/bin/bash +``` + +#### 3、Break 结束循环 + +##### 1、Break 结束循环实例 + +break[n]:当第n次循环到来后,结束整个循环,n=0就是指本次循环 + +当计算的和大于 50 的时候使用 break 结束循环: + +```shell +[root@qfedu.com ~]# awk 'BEGIN { + sum = 0; for (i = 0; i < 20; ++i) { + sum += i; if (sum > 50) break; else print "Sum =", sum + } +}' + +Sum = 0 +Sum = 1 +Sum = 3 +Sum = 6 +Sum = 10 +Sum = 15 +Sum = 21 +Sum = 28 +Sum = 36 +Sum = 45 +``` + +#### 4、Continue 跳出本次循环 + +Continue 语句用于在循环体内部结束本次循环,从而直接进入下一次循环迭代。 + +Continue[n]:满足条件后,直接进行第n次循环,本次循环不在进行,n=0也就是提前结束本次循环而直接进入下一轮 + +输出 1 到 20 之间的偶数: + +```shell +[root@qfedu.com ~]# awk 'BEGIN {for (i = 1; i <= 20; ++i) {if (i % 2 == 0) print i ; else continue} }' +2 +4 +6 +8 +10 +12 +14 +16 +18 +20 +``` + +#### 5、Exit 结束脚本程序 + +Exit 用于结束脚本程序的执行。 + +该函数接受一个整数作为参数表示 AWK 进程结束状态。 如果没有提供该参数,其默认状态为 0。 + +当和大于 50 时结束 AWK 程序。 + +```shell +[root@qfedu.com ~]# awk 'BEGIN { + sum = 0; for (i = 0; i < 20; ++i) { + sum += i; if (sum > 50) exit(10); else print "Sum =", sum + } +}' + +Sum = 0 +Sum = 1 +Sum = 3 +Sum = 6 +Sum = 10 +Sum = 15 +Sum = 21 +Sum = 28 +Sum = 36 +Sum = 45 +``` + +检查脚本执行后的返回状态 + +```shell +[root@qfedu.com ~]# echo $? +10 +``` + +#### 6、Next 停止处理 + +next:提前结束对本行的处理动作而直接进入下一行处理 + + +```shell +[root@qfedu.com ~]# awk -F: '{if($3%2!=0) next; print $1,$3}' /etc/passwd +``` + +## 十一、AWK 数组 + +AWK 可以使用关联数组这种数据结构,索引可以是数字或字符串。 + +AWK关联数 组也不需要提前声明其大小,因为它在运行时可以自动的增大或减小。 + +### 1、数组语法格式 + +```shell +array_name[index]=value +``` + +- array_name:数组的名称 +- index:数组索引 +- value:数组中元素所赋予的值 + +### 2、创建数组 + +定义了一个站点(sites)数组,该数组的索引为网站英文简称,值为网站访问地址。 + +```shell +[root@qfedu.com ~]# awk 'BEGIN { +sites["qfedu"]="www.qfedu.com"; +sites["google"]="www.google.com" +print sites["qfedu"] "\n" sites["google"] +}' +www.qfedu.com +www.google.com +``` + +### 3、访问数组元素 + +#### 1、访问数组元素语法格式 + +```shell +array_name[index] +``` + +#### 2、访问数组元素 + +```sh +[root@qfedu.com ~]# awk -F: '{username[++i]=$1} END{print username[1]}' /etc/passwd +root +[root@qfedu.com ~]# awk -F: '{username[i++]=$1} END{print username[1]}' /etc/passwd +bin +[root@qfedu.com ~]# awk -F: '{username[i++]=$1} END{print username[0]}' /etc/passwd +root +``` + +#### 3、按元数个数遍历 + +```shell +[root@qfedu.com ~]# awk -F: '{username[x++]=$1} END{for(i=0;iv2?var=v1:var=v2 + return var + } + BEGIN{a=3;b=2;print max(a,b)} +awk –f fun.awk +``` + +## 十三、课下练习 + +1、AWK 日志分析统计 + +```shell +# 统计一个时间范围内访(pv)问量 +[root@qfedu.com ~]# grep '01/Sep/2017' sz.mobiletrain.org.log | wc -l +[root@qfedu.com ~]# awk '$4>="[05/Sep/2017:08:00:00" && $4<="[05/Sep/2017:09:00:00" {print $0}' sz.mobiletrain.org.log | wc -l + +# 统计一个时间范围内访问量前10的ip +[root@qfedu.com ~]# grep '05/Sep/2017' cd.mobiletrain.org.log | awk '{ips[$1]++} END{ for(i in ips){print i ,ips[i]}}' | sort -k2 -rn | head + +[root@qfedu.com ~]# awk '/05\/Sep\/2017/ {ips[$1]++} END{ for(i in ips){print i ,ips[i]}}' cd.mobiletrain.org.log | sort -k2 -rn | head + +# 统计一个时间范围内访问前10的页面 +[root@qfedu.com ~]# grep '05/Sep/2017' cd.mobiletrain.org.log | awk '{ urls[$7]++} END{for(i in urls){print urls[i],i}}'|sort -k1 -rn |head + +[root@qfedu.com ~]# awk '/05\/Sep\/2017/ { urls[$7]++} END{for(i in urls){print urls[i],i}}' cd.mobiletrain.org.log |sort -k1 -rn |head + +# 统计一个时间范围内访问大于100次的ip +[root@qfedu.com ~]# grep '05/Sep/2017' sz.mobiletrain.org.log | awk '{ ips[$1]++ } END{for (i in ips) {if(ips[i]>100) {print i,ips[i]}}}' +[root@qfedu.com ~]# awk '/05\/Sep\/2017/ { ips[$1]++ } END{for (i in ips) {if(ips[i]>100) {print i,ips[i]}}}' sz.mobiletrain.org.log + +# 统计一个时间范围访问前10的url +[root@qfedu.com ~]# awk '/05\/Sep\/2017/{urls[$7]++} END{for(i in urls){print i,urls[i]}}' sz.mobiletrain.org.log |sort -k2rn |head + +# 统计一个时间范围内url访问总大小前10的url +[root@qfedu.com ~]# grep '05/Sep/2017' sz.mobiletrain.org.log | awk '{ urls[$7]++; size[$7]+=$10} END { for(i in urls ) { print urls[i],size[i],i}}'| sort -k1 -rn |head + +[root@qfedu.com ~]# awk '/05\/Sep\/2017/{size[$7]+=$10} END{for(i in size){print i,size[i]}}' sz.mobiletrain.org.log |sort -k2rn |head + +# 统计一个时间范围内每个访问ip的状态码数量 +[root@qfedu.com ~]# grep '05/Sep/2017' sz.mobiletrain.org.log | awk '{ ip_code[ $1" "$9]++} END{ for(i in ip_code) {print i,ip_code[i]}}'| sort -k1 -rn | head + +[root@qfedu.com ~]# awk '/05\/Sep\/2017/{ip_code[$1" "$9]++} END{for(i in ip_code){print i,ip_code[i]}}' sz.mobiletrain.org.log |sort -k1rn |head + +# 统计一个时间范围内访问状态码时404的ip +[root@qfedu.com ~]# grep '05/Sep/2017' sz.mobiletrain.org.log | awk '{if($9="404"){ip_code[$1" "$9]++}} END{for(i in ip_code){print i,ip_code[i]}}'|sort -k3 -rn + +[root@qfedu.com ~]# awk '$4>="[05/Sep/2017:08:00:00" && $4<="[05/Sep/2017:09:00:00" {if($9="404"){ip_code[$1" "$9]++}} END{for(i in ip_code){print i,ip_code[i]}}' sz.mobiletrain.org.log |sort -k3 -rn + +[root@qfedu.com ~]# awk '/05\/Sep\/2017/{if($9=="404"){ip_code[$1" "$9]++}} END{for(i in ip_code){print i,ip_code[i]}}' sz.mobiletrain.org.log |sort -k3rn |head + +# 统计前一分钟的访问量 +[root@qfedu.com ~]# date=$(date -d '1 minute' +%d/%b/%Y:%H:%M); awk -v date=$date '$0 ~ date {i++} END{print i}' sz.mobiletrain.org.log +# 统计一个时间范围内出现的各种状态码 +[root@qfedu.com ~]# grep '05/Sep/2017' sz.mobiletrain.org.log | awk '{code[$9]++} END{for(i in code){print i, code[i]}}' +[root@qfedu.com ~]# awk '/05\/Sep\/2017/ {code[$9]++}END{for(i in code){print i ,code[i]}}' sz.mobiletrain.org.log +[root@qfedu.com ~]# grep '05/Sep/2017' sz.mobiletrain.org.log | awk '{code[$9]++; total++} END{for(i in code){printf i" "; printf code[i]"\t";printf"%.2f", code[i]/total*100;print"%"}}' + +[root@qfedu.com ~]# awk '/05\/Sep\/2017/{code[$9]++; total++} END{for(i in code){printf i " "; printf code[i]"\t"; printf"%.2f",code[i]/total*100;print"%"}}' sz.mobiletrain.org.log +``` + +2、AWK 统计 tcp 连接 + +```shell +[root@qfedu.com ~]# ss -an | grep ^tcp|awk '{tcp_connect_status[$2]++}END{for(i in tcp_connect_status) {print i, tcp_connect_status[i]}}' +``` + +3、AWK 获取硬件信息 + +```shell +#!/bin/bash +yum install hdparm dmidecode pciutils -y +echo +echo "###### CPU #######" +echo +cat /proc/cpuinfo | grep "model name"| awk -F ":" '{print $2}'| uniq -f 1 +cat /proc/cpuinfo | grep "cpu cores"| awk -F ":" '{print " CPU ="$2}'| uniq -f 1 +echo +echo "###### Hard Disk ######" +echo +hdparm -i /dev/sda | grep -i "model"| awk -F"-" '{print $1}'| awk -F "=" '{print $2}' +fdisk -l | grep "/dev/sda"| awk -F "," 'NR==1{print $1}' +echo +df -h +echo +echo "###### Memory ######" +echo +dmidecode -t memory | grep -i "maximum capacity" +dmidecode -t memory | grep -i "number of devices" +echo +dmidecode -t memory | grep -i "size"| awk -F ":" 'NR==1{print " Capacity 1" $1":",$2}' +dmidecode -t memory | grep -i "speed"| awk 'NR==1' +dmidecode -t memory | grep -i "type:"| uniq -f 1 +dmidecode -t memory | grep -i "size"| awk -F ":" 'NR==2{print " Capacity 2" $1":",$2}' +dmidecode -t memory | grep -i "speed"| awk 'NR==2' +dmidecode -t memory | grep -i "type:"| uniq -f 1 +dmidecode -t memory | grep -i "size"| awk -F ":" 'NR==3{print " Capacity 3" $1":",$2}' +dmidecode -t memory | grep -i "speed"| awk 'NR==3' +dmidecode -t memory | grep -i "type:"| uniq -f 1 +dmidecode -t memory | grep -i "size"| awk -F ":" 'NR==4{print " Capacity 4" $1":",$2}' +dmidecode -t memory | grep -i "speed"| awk 'NR==4' +dmidecode -t memory | grep -i "type:"| uniq -f 1 +echo +free -m +echo +echo "###### Mianboard ######" +echo +dmidecode -q | grep -i "product name"| awk -F":" 'NR==1{print "Server Model" ":",$2}' +dmidecode -q | grep -i "Manufacturer"| awk -F":" 'NR==1{print "Brand" ":",$2}' +dmidecode -q | grep -i "product name"| awk -F":" 'NR==2{print "Mainboard Model" ":",$2}' +echo +echo "###### Network Card ######" +echo +lspci | grep -i eth | awk 'NR==1'| awk -F ":" '{print $3}' +echo +echo "###### Operating System ######" +echo +cat /etc/issue | awk 'NR==1' +uname -r | awk '{print "kernel: "$1}' +echo +``` + +4、AWK 获取系统状态信息 + +```shell +#!/bin/bash +#show system information +PS3="Your choice is: " +os_check() { + if [ -e /etc/redhat-release ]; then + REDHAT=`cat /etc/redhat-release |cut -d' ' -f1` + else + DEBIAN=`cat /etc/issue |cut -d' ' -f1` + fi + + if [ "$REDHAT" == "CentOS" -o "$REDHAT" == "Red" ]; then + P_M=yum + elif [ "$DEBIAN" == "Ubuntu" -o "$DEBIAN" == "ubutnu" ]; then + P_M=apt-get + else + Operating system does not support. + exit 1 + fi +} + +if [ $LOGNAME != root ]; then + echo "Please use the root account operation." + exit 1 +fi + +if ! which vmstat &>/dev/null; then + echo "vmstat command not found, now the install." + sleep 1 + os_check + $P_M install procps -y + echo "-----------------------------------------------------------------------" +fi + +which iostat &>/dev/null +if [ $? -ne 0 ]; then + echo "iostat command not found, now the install." + sleep 1 + os_check + $P_M install sysstat -y + echo "-----------------------------------------------------------------------" +fi + +while true; do + select input in cpu_load disk_load disk_use disk_inode mem_use tcp_status cpu_top10 mem_top10 traffic quit; do + case $input in + cpu_load) + #CPU利用率与负载 + echo "---------------------------------------" + i=1 + while [[ $i -le 3 ]]; do + echo -e "\033[32m 参考值${i}\033[0m" + UTIL=`vmstat |awk '{if(NR==3)print 100-$15"%"}'` + USER=`vmstat |awk '{if(NR==3)print $13"%"}'` + SYS=`vmstat |awk '{if(NR==3)print $14"%"}'` + IOWAIT=`vmstat |awk '{if(NR==3)print $16"%"}'` + echo "Util: $UTIL" + echo "User use: $USER" + echo "System use: $SYS" + echo "I/O wait: $IOWAIT" + let i++ + sleep 1 + done + echo "---------------------------------------" + break + ;; + disk_load) + #硬盘I/O负载 + echo "---------------------------------------" + i=1 + while [[ $i -le 3 ]]; do + echo -e "\033[32m 参考值${i}\033[0m" + UTIL=`iostat -x -k |awk '/^[v|s]/{OFS=": ";print $1,$NF"%"}'` + READ=`iostat -x -k |awk '/^[v|s]/{OFS=": ";print $1,$6"KB"}'` + WRITE=`iostat -x -k |awk '/^[v|s]/{OFS=": ";print $1,$7"KB"}'` + IOWAIT=`vmstat |awk '{if(NR==3)print $16"%"}'` + echo -e "Util:" + echo -e "${UTIL}" + echo -e "I/O Wait: $IOWAIT" + echo -e "Read/s:\n$READ" + echo -e "Write/s:\n$WRITE" + i=$(($i+1)) + sleep 1 + done + echo "---------------------------------------" + break + ;; + disk_use) + #硬盘利用率 + DISK_LOG=/tmp/disk_use.tmp + DISK_TOTAL=`fdisk -l |awk '/^Disk.*bytes/ && /\/dev/{printf $2" ";printf "%d",$3;print "GB"}'` + USE_RATE=`df -h |awk '/^\/dev/{print int($5)}'` + for i in $USE_RATE; do + if [ $i -gt 90 ];then + PART=`df -h |awk '{if(int($5)=='''$i''') print $6}'` + echo "$PART = ${i}%" >> $DISK_LOG + fi + done + echo "---------------------------------------" + echo -e "Disk total:\n${DISK_TOTAL}" + if [ -f $DISK_LOG ]; then + echo "---------------------------------------" + cat $DISK_LOG + echo "---------------------------------------" + rm -f $DISK_LOG + else + echo "---------------------------------------" + echo "Disk use rate no than 90% of the partition." + echo "---------------------------------------" + fi + break + ;; + disk_inode) + #硬盘inode利用率 + INODE_LOG=/tmp/inode_use.tmp + INODE_USE=`df -i |awk '/^\/dev/{print int($5)}'` + for i in $INODE_USE; do + if [ $i -gt 90 ]; then + PART=`df -h |awk '{if(int($5)=='''$i''') print $6}'` + echo "$PART = ${i}%" >> $INODE_LOG + fi + done + if [ -f $INODE_LOG ]; then + echo "---------------------------------------" + cat $INODE_LOG + rm -f $INODE_LOG + else + echo "---------------------------------------" + echo "Inode use rate no than 90% of the partition." + echo "---------------------------------------" + fi + break + ;; + mem_use) + #内存利用率 + echo "---------------------------------------" + MEM_TOTAL=`free -m |awk '{if(NR==2)printf "%.1f",$2/1024}END{print "G"}'` + USE=`free -m |awk '{if(NR==2) printf "%.1f",$3/1024}END{print "G"}'` + FREE=`free -m |awk '{if(NR==2) printf "%.1f",$4/1024}END{print "G"}'` + CACHE=`free -m |awk '{if(NR==2) printf "%.1f",$6/1024}END{print "G"}'` + echo -e "Total: $MEM_TOTAL" + echo -e "Use: $USE" + echo -e "Free: $FREE" + echo -e "Cache: $CACHE" + echo "---------------------------------------" + break + ;; + tcp_status) + #网络连接状态 + echo "---------------------------------------" + COUNT=`ss -ant |awk '!/State/{status[$1]++}END{for(i in status) print i,status[i]}'` + echo -e "TCP connection status:\n$COUNT" + echo "---------------------------------------" + ;; + cpu_top10) + #占用CPU高的前10个进程 + echo "---------------------------------------" + CPU_LOG=/tmp/cpu_top.tmp + i=1 + while [[ $i -le 3 ]]; do + #ps aux |awk '{if($3>0.1)print "CPU: "$3"% -->",$11,$12,$13,$14,$15,$16,"(PID:"$2")" |"sort -k2 -nr |head -n 10"}' > $CPU_LOG + ps aux |awk '{if($3>0.1){{printf "PID: "$2" CPU: "$3"% --> "}for(i=11;i<=NF;i++)if(i==NF)printf $i"\n";else printf $i}}' |sort -k4 -nr |head -10 > $CPU_LOG + #循环从11列(进程名)开始打印,如果i等于最后一行,就打印i的列并换行,否则就打印i的列 + if [[ -n `cat $CPU_LOG` ]]; then + echo -e "\033[32m 参考值${i}\033[0m" + cat $CPU_LOG + > $CPU_LOG + else + echo "No process using the CPU." + break + fi + let i++ + sleep 1 + done + echo "---------------------------------------" + break + ;; + mem_top10) + #占用内存高的前10个进程 + echo "---------------------------------------" + MEM_LOG=/tmp/mem_top.tmp + i=1 + while [[ $i -le 3 ]]; do + #ps aux |awk '{if($4>0.1)print "Memory: "$4"% -->",$11,$12,$13,$14,$15,$16,"(PID:"$2")" |"sort -k2 -nr |head -n 10"}' > $MEM_LOG + ps aux |awk '{if($4>0.1){{printf "PID: "$2" Memory: "$4"% --> "}for(i=11;i<=NF;i++)if(i==NF)printf $i"\n";else printf $i}}' |sort -k4 -nr |head -10 > $MEM_LOG + if [[ -n `cat $MEM_LOG` ]]; then + echo -e "\033[32m 参考值${i}\033[0m" + cat $MEM_LOG + > $MEM_LOG + else + echo "No process using the Memory." + break + fi + i=$(($i+1)) + sleep 1 + done + echo "---------------------------------------" + break + ;; + traffic) + #查看网络流量 + while true; do + read -p "Please enter the network card name(eth[0-9] or em[0-9] or team[0-9]): " eth + if [ `ifconfig |grep -c "\<$eth\>"` -eq 1 ]; then + break + else + echo "Input format error or Don't have the card name, please input again." + fi + done + echo "---------------------------------------" + echo -e " In ------ Out" + i=1 + while [[ $i -le 3 ]]; do + #CentOS6和CentOS7 ifconfig输出进出流量信息位置不同: + #CentOS6中RX与TX行号等于8 + #CentOS7中RX行号是5,TX行号是7 + + OLD_IN=`ifconfig $eth |awk -F'[: ]+' '/bytes/{if(NR==8)print $4;else if(NR==5)print $6}'` + OLD_OUT=`ifconfig $eth |awk -F'[: ]+' '/bytes/{if(NR==8)print $9;else if(NR==7)print $6}'` + sleep 1 + NEW_IN=`ifconfig $eth |awk -F'[: ]+' '/bytes/{if(NR==8)print $4;else if(NR==5)print $6}'` + NEW_OUT=`ifconfig $eth |awk -F'[: ]+' '/bytes/{if(NR==8)print $9;else if(NR==7)print $6}'` + + IN=`awk 'BEGIN{printf "%.1f\n",'$((${NEW_IN}-${OLD_IN}))'/1024/128}'` + OUT=`awk 'BEGIN{printf "%.1f\n",'$((${NEW_OUT}-${OLD_OUT}))'/1024/128}'` + echo "${IN}MB/s ${OUT}MB/s" + + i=$(($i+1)) + sleep 1 + done + echo "---------------------------------------" + break + ;; + quit) + exit 0 + ;; + *) + echo "---------------------------------------" + echo "Please enter the number." + echo "---------------------------------------" + break + ;; + esac + done +done + +``` + +5、Linux 系统初始化脚本 + +```shell +#!/bin/bash + +# get os version +RELEASEVER=$(rpm -q --qf "%{VERSION}" $(rpm -q --whatprovides redhat-release)) + +# configure yum source +cd /etc/yum.repos.d/ +mkdir /etc/yum.repos.d/bak +mv /etc/yum.repos.d/*.repo /etc/yum.repos.d/bak +if [ $RELEASEVER == 6 ];then +    curl http://mirrors.163.com/.help/CentOS6-Base-163.repo > qf.repo +fi +if [ $RELEASEVER == 7 ];then +    curl http://mirrors.163.com/.help/CentOS7-Base-163.repo > qf.repo +fi +yum clean all +yum check-update + +# install base rpm package +yum -y insall epel-release +yum -y install nc vim iftop iotop dstat tcpdump +yum -y install ipmitool bind-libs bind-utils +yum -y install libselinux-python ntpdate + +# update rpm package include kernel +yum -y update +rm -rf /etc/yum.repos.d/CentOS* + +# update ulimit configure +if [ $RELEASEVER == 6 ];then +    test -f /etc/security/limits.d/90-nproc.conf && rm -rf /etc/security/limits.d/90-nproc.conf && touch /etc/security/limits.d/90-nproc.conf +fi +if [ $RELEASEVER == 7 ];then +    test -f /etc/security/limits.d/20-nproc.conf && rm -rf /etc/security/limits.d/20-nproc.conf && touch /etc/security/limits.d/20-nproc.conf +fi + +> /etc/security/limits.conf +cat >> /etc/security/limits.conf < /dev/null 2>&1' > /var/spool/cron/root;chmod 600 /var/spool/cron/root +    fi +    /etc/init.d/crond restart +fi + +if [ $RELEASEVER == 7 ];then +    yum -y install chrony +    > /etc/chrony.conf +cat > /etc/chrony.conf << EOF +server pool.ntp.org iburst +stratumweight 0 +driftfile /var/lib/chrony/drift +rtcsync +makestep 10 3 +bindcmdaddress 127.0.0.1 +bindcmdaddress ::1 +keyfile /etc/chrony.keys +commandkey 1 +generatecommandkey +noclientlog +logchange 0.5 +logdir /var/log/chrony +EOF + + systemctl restart chronyd + systemctl enable chronyd +fi + +# clean iptables default rules +if [ $RELEASEVER == 6 ];then +    /sbin/iptables -F +    service iptables save +    chkconfig iptables off +fi +if [ $RELEASEVER == 7 ];then +    systemctl disable firewalld +fi + +# disable unused service +chkconfig auditd off + +# disable ipv6 +cd /etc/modprobe.d/ && touch ipv6.conf +> /etc/modprobe.d/ipv6.conf +cat >> /etc/modprobe.d/ipv6.conf << EOF +alias net-pf-10 off +alias ipv6 off +EOF + +# disable iptable nat moudule +cd /etc/modprobe.d/ && touch connectiontracking.conf +> /etc/modprobe.d/connectiontracking.conf +cat >> /etc/modprobe.d/connectiontracking.conf <> /etc/profile +fi + +# install dsnmasq and update configure +yum -y install dnsmasq +> /etc/dnsmasq.conf +cat >> /etc/dnsmasq.conf<< EOF +listen-address=127.0.0.1 +no-dhcp-interface=lo +log-queries +log-facility=/var/log/dnsmasq.log +all-servers +no-negcache +cache-size=1024 +dns-forward-max=512 +EOF + +if [ $RELEASEVER == 6 ];then +    /etc/init.d/dnsmasq restart +fi + +if [ $RELEASEVER == 7 ];then +    systemctl restart dnsmasq + systemctl enable dnsmasq +fi + +# update /etc/resolv.conf +> /etc/resolv.conf +cat >> /etc/resolv.conf<< EOF +options timeout:1 +nameserver 127.0.0.1 +nameserver 114.114.114.114 +EOF + +# update /etc/sysctl.conf +cat >> /etc/sysctl.conf<< EOF +net.ipv4.tcp_syncookies = 1 +kernel.core_uses_pid=1 +kernel.core_pattern=/tmp/core-%e-%p +fs.suid_dumpable=2 +net.ipv4.tcp_tw_reuse=1 +net.ipv4.tcp_tw_recycle=0 +net.ipv4.tcp_timestamps=1 +EOF +sysctl -p +``` + +6、LAMP环境部署 + +```shell +#!/bin/bash +cat <<-EOF ++-------------------------------------------------------------------------+ +| LAMP环境部署 V1.0 | ++-------------------------------------------------------------------------+ +| a. 部署Apache服务 | +| b. 部署php服务 | +| c. 部署Mysql服务 | +| d. 一键部署LAMP | +| q. 按q键退出程序 | ++-------------------------------------------------------------------------+ +EOF +# 安装Apache +install_Apache() +{ +systemctl stop firewalld +systemctl disable firewalld +setenforce 0 +sed -i '/^\bSELINUX\b/c SELINUX=disabled' /etc/selinux/config +mkdir /usr/local/apr &> /dev/null +mkdir /usr/local/apr-util &> /dev/null +mkdir /usr/local/apache &> /dev/null +cd /usr/local/src +echo "正在下载Apache服务,请稍等!!!" +wget http://archive.apache.org/dist/apr/apr-1.6.5.tar.gz &> /dev/null +wget http://archive.apache.org/dist/apr/apr-util-1.6.1.tar.gz &> /dev/null +wget http://mirrors.hust.edu.cn/apache/httpd/httpd-2.4.37.tar.gz &> /dev/null +if [ $? -eq 0 ] +then +echo "download success" +else +echo "download failed" +exit +fi +tar xf apr-1.6.5.tar.gz +tar xf apr-util-1.6.1.tar.gz +tar xf httpd-2.4.37.tar.gz +echo "正在安装所需的依赖包" +yum -y install gcc gcc-c++ openssl openssl-devel expat-devel &> /dev/null +if [ $? -eq 0 ] +then +echo "依赖包安装成功" +else +echo "依赖包安装失败" +exit +fi +cd /usr/local/src/apr-1.6.5/ +echo "正在配置和编译安装apr,请喝口水稍等!!!" +./configure --prefix=/usr/local/apr/ &> /dev/null +make &> /dev/null && make install &>/dev/null +if [ $? -eq 0 ] +then +echo "apr installed" +else +echo "apr installed failed" +exit +fi +cd /usr/local/src/apr-util-1.6.1/ +./configure --prefix=/usr/local/apr-util --with-apr=/usr/local/apr/ &> /dev/null +make &> /dev/null && make install &> /dev/null +if [ $? -eq 0 ] +then +echo "apr-util installed" +else +echo "apr-util installed failed" +exit +fi +cd /usr/local/src/httpd-2.4.37/ +echo "正在配置Apache" +./configure --prefix=/usr/local/apache/ --with-apr=/usr/local/apr/ --with-apr-util=/usr/local/apr-util/ --enable-so --enable-ssl--enable-deflate=shared --enable-expires=shared --enable-rewrite=shared --enable-static-support &> /dev/null +make &> /dev/null && make install &> /dev/null +if [ $? -eq 0 ] +then +echo "Apache installed" +else +echo "Apache installed failed" +exit +fi +cd /usr/local/apache/bin/ +echo ServerName www.fangxi.com >> /usr/local/apache/conf/httpd.conf +./apachectl start +if [ $? -eq 0 ] +then +echo "Apache安装成功并启动" +else +echo "Apache启动失败" +exit +fi +} + +#安装php +install_php() +{ +echo "正在安装php服务" +yum -y install php php-cli php-curl php-fpm php-intl php-mcryp php-mysql php-gd php-mbstring php-xml php-dom &> /dev/null +if [ $? -eq 0 ] +then +echo "php安装成功" +else +echo "php安装失败" +exit +fi +systemctl start php-fpm &> /dev/null +if [ $? -eq 0 ] +then +echo "php安装成功" +else +echo "php安装失败" +exit +fi + +} +#编译安装Mysql +install_mysql() +{ +echo "开始安装mysql" +echo "正在准备编译环境,wait a minute" +yum -y install ncurses ncurses-devel openssl-devel bison gcc gcc-c++ make cmake &> /dev/null +if [ $? -eq 0 ] +then +echo "编译环境已准备好" +else +echo "编译环境准备失败" +exit +fi +echo "正在下载源码包----请稍稍等一下" +wget http://ftp.ntu.edu.tw/MySQL/Downloads/MySQL-5.7/mysql-boost-5.7.26.tar.gz +groupadd mysql +useradd -r -g mysql -s /bin/nologin mysql +tar xf mysql-boost-5.7.26.tar.gz +cd mysql-5.7.26/ +echo "正在配置中,请再喝口水,小憩一下" +cmake . \ +-DWITH_BOOST=boost/boost_1_59_0/ \ +-DCMAKE_INSTALL_PREFIX=/usr/local/mysql \ +-DSYSCONFDIR=/etc \ +-DMYSQL_DATADIR=/usr/local/mysql/data \ +-DINSTALL_MANDIR=/usr/share/man \ +-DMYSQL_TCP_PORT=3306 \ +-DMYSQL_UNIX_ADDR=/tmp/mysql.sock \ +-DDEFAULT_CHARSET=utf8 \ +-DEXTRA_CHARSETS=all \ +-DDEFAULT_COLLATION=utf8_general_ci \ +-DWITH_READLINE=1 \ +-DWITH_SSL=system \ +-DWITH_EMBEDDED_SERVER=1 \ +-DENABLED_LOCAL_INFILE=1 \ +-DWITH_INNOBASE_STORAGE_ENGINE=1 &> /dev/null +if [ $? -eq 0 ] +then +echo "mysql配置成功" +else +echo "mysql配置失败" +exit +fi +echo "----------正在安装编译安装Mysql请稍等-----------" +make &> /dev/null && make install /dev/null +if [ $? -eq 0 ] +then +echo "mysql编译安装成功" +else +echo "mysql编译安装失败" +exit +fi +echo [mysqld] > /etc/my.cnf +echo basedir=/usr/local/mysql >> /etc/my.cnf +echo datadir=/usr/local/mysql/data >> /etc/my.cnf +echo "mysql配置文件successed" +cd /usr/local/mysql/ +mkdir mysql-files +chown -R mysql.mysql /usr/local/mysql +echo "-------------正在初始化Mysql请稍等--------------" +/usr/local/mysql/bin/mysqld --initialize --user=mysql --basedir=/usr/local/mysql --datadir=/usr/local/mysql/data &> mima.txt +mima=awk '/password/ {print $NF}' mima.txt +echo "初始密码为:$mima" +if [ $? -eq 0 ] +then +echo "mysql初始化成功" +else +echo "mysql初始化失败" +exit +fi +bin/mysql_ssl_rsa_setup --datadir=/usr/local/mysql/data +#给数据库加密 +cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld +chkconfig --add mysqld +chkconfig mysqld on +#添加到开机启动项 +systemctl start mysqld +if [ $? -eq 0 ] +then +echo "mysql启动成功" +else +echo "mysql启动失败" +exit +fi +echo "export PATH=$PATH:/usr/local/mysql/bin" >> /etc/profile +source /etc/profile +echo "----------修改数据库初始密码----------" +read -p "请输入你要设置的数据库密码" new_mima +mysqladmin -uroot -p${mima} password "$new_mima" +if [ $? -eq 0 ] +then +echo "mysql初始密码修改成功,mysql部署完成" +else +echo "mysql初始密码修改失败" +exit +fi + +} +while : +do +read -p "请输入你要选择的参数: " var +case $var in +a) +install_Apache +;; +b) +install_php +;; +c) +install_mysql +;; +d) +install_Apache +install_php +install_mysql +;; +q) +exit +;; +*) +printf "请按照上方提供的选项输入!!!\n" +;; +esac +done +``` +