Shell脚本基本知识(变量,条件语句,正则表达式,grep,与awk)

230 阅读13分钟

1 前言

面向过程语言

  • 做一件事情,排出个步骤,第一步干什么,第二步干什么,如果出现情况A,做什么处理,如果出现了情况B,做什么处理
  • 问题规模小,可以步骤化,按部就班处理
  • 以指令为中心,数据服务于指令

有这些语言 C,shell

面向对象语言

  • 将编程看成是一个事物,对外界来说,事物是直接使用的,不用关心事物内部的情况。而编程就是设置事物能够完成功能。
  • 一种认识世界、分析世界的方法论。将万事万物抽象为各种对象
  • 类是抽象的概念,是万事万物的抽象,是一类事物的共同特征的集合
  • 对象是类的具象,是一个实体
  • 问题规模大,复杂系统
  • 以数据为中心,指令服务于数据

有这些语言java,python,golang等 云 go k8个字母s 平台

2 shell脚本

2.1shell的作用

Linux 系统中的 Shell 是一个特殊的应用程序,它介于操作系统内核与用户之间,充当 了一个“命令解释器”的角色,负责接收用户输入的操作指令(命令)并进行解释,将需要执 行的操作传递给内核执行,并输出执行结果。 常见的 Shell 解释器程序有很多种,使用不同的 Shell 时,其内部指令、命令行提示符 等方面会存在一些区别。通过/etc/shells 文件可以了解当前系统所支持的 Shell 脚本种类。

[root@test1 ~]# cat /etc/shells              //查看当前的系统支持的shell
/bin/sh
/bin/bash
/sbin/nologin
/usr/bin/sh
/usr/bin/bash
/usr/sbin/nologin
/bin/tcsh
/bin/csh
[root@test1 ~]# useradd -s 

image.png

shell脚本的用途

  • 将简单的命令组合完成复杂的工作,自动化执行命令,提高工作效率
  • 减少手工命令的重复输入,一定程度上避免人为错误
  • 将软件或应用的安装及配置实现标准化
  • 用于实现日常性的,重复性的运维工作,如:文件打包压缩备份,监控系统运行状态并实现告警等

2.2 什么是shell脚本及构成

脚本就是将命令按顺序一一列出,最后自动执行,俗称:屎山脚本

执行需要权限,也可以直接使用绝对路径

脚本其实不复杂,通用脚本环境改变后依然可以使用的脚本

脚本的构成

  1. 脚本申明(解释器):第一行开头“#!/bin/bash”,表示此行以下的代码语句是通过/bin/bash程序来解释执行。#!/bin/bash为默认的解释器还有其他类型的解释器,#!/bin/python #!/bin/expect
  2. 注释信息:以#开头的语句表示为注释信息
  3. 可执行语句、命令:比如echo命令用于输出" "之间的字符串
[root@localhost ~]# vim 1.sh
echo "hello world"
[root@localhost ~]# ./1.sh 
#!/bin/bash
hello world

image.png

image.png

2.3shell脚本的执行逻辑及执行方式

脚本的执行逻辑

顺序执行:程序按从上到下顺序执行

选择执行:程序执行过程中,根据条件的不同,进行选择不同分支继续执行

循环执行:程序执行过程中需要重复执行多次某段语句

执行方式:

1.指定路径去执行文件(需要有执行权限)

[root@localhost ~]# chmod +x /root/host.sh    加权限
指定相对路径./host.sh
指定绝对路径/root/host.sh

image.png

2.指定解释器去执行(不需要权限)

image.png

3.使用source和'.'去启动,但是不建议使用,会影响当前环境

image.png

2.4 脚本会出现的错误

1.命令错误:默认后续的命令还会继续执行,用bash -x进行检查

2.语法错误:可以使用bash -n 检查错误,错误的行数不一定准确

3.逻辑错误:只能自己去筛查

2.5重定向与管道符

2.5.1重定向

类型设备文件文件描述编号默认设备
标准输入/dev/stdin0键盘
标准输出/dev/stdout1显示器
标准错误输出/dev/stderr2显示器

标准输入:从该设备接收用户输入的数据

标准输出:通过该设备向用户输出的数据

标准错误:通过该设备报告执行出错的信息

重定向的意思就是,不通过标准输出到屏幕上,输出到自己指定的位置

类型操作符用途
重定向输入<从指定的文件读取数据,而不是从键盘输入
重定向输出1>将输出结果保存到指定的文件(覆盖原有内容)
>>将输出结果追加到指定的文件尾部
标准错误输出2>将错误信息保存到指定的文件(覆盖原有内容)
2>>标准错误输出结果追加到指定的文件尾部
混合输出&>无论对错都可以重定向将标准输出、标准错误的内容保存到同一个文件中
1为正确输出
[root@localhost ~]#ls >/opt/1
#打开两个终端,ls命令显示到终端1上 标准重定向省略了1>

image.png

2为错误输出
[root@localhost data]#ls xxx 2>/opt/2
[root@localhost data]#ls/opt/2
-bash: ls/opt/2: 没有那个文件或目录
[root@localhost data]#

image.png

[root@localhost ~]#ls /data /error >all.log 2>&1
#既有错误也有正确 &符号表示分隔符
[root@localhost ~]#cat all.log 
ls: 无法访问/error: 没有那个文件或目录
/data:
apr-1.6.2.tar.gz
apr-util-1.6.0.tar.gz
httpd-2.4.29.tar.bz2

image.png

2.5.2 多行重定向

Here Document 概述 使用 I/O 重定向的方式将命令列表提供给交互式程序或命令,比如 ftp、cat 或 read 命令。 HereDocument是标准输入的一种替代品, 可以帮助脚本开发人员不必使用临时文件来构建输入信息, 而是直接就地生产出一个文件并用作命令的标准输入。

#####将内容写入   文件
[root@localhost data]#cat >1.txt <<EOF
> 123
> 345
> 567
> EOF



#####修改密码
[root@localhost data]#passwd zhangsan <<EOF
> 123123
> 123123
> EOF
更改用户 zhangsan 的密码 。
新的 密码:无效的密码: 密码少于 8 个字符
重新输入新的 密码:passwd:所有的身份验证令牌已经成功更新。

###变量赋值
[root@localhost ~]# read a <<EOF
> 10
> EOF
[root@localhost ~]# echo $a
10
[root@localhost data]#read i <<EOF
> lzq
> EOF
[root@localhost data]#echo $i
lzq

image.png

3.变量

3.1 常见的shell变量类型

自定义变量:由用户自己定义,修改和使用
环境变量:由系统维护,用于设置工作环境
只读变量:只可以读取不可以更改
位置变量:通过命令行给脚本传递参数
预定义变量:Bash中内置的一类变量,不能修改    有些规定好的变量 放在那里让你使用

3.2 变量命名的要求

  • 区分大小写
  • 不能使程序中的保留字和内置变量:如:if, for,hostname 命令
  • 只能使用数字、字母及下划线,且不能以数字开头,注意:不支持短横线 “ - ”,和主机名相反
  • 不要使用内置的变量,使用英文尽量使用词义通俗易懂,PATH

自定义变量:

  • name='value'
  • 变量名=变量值
  • 直接字串:name='root'
  • 变量引用:name="$USER"
  • 命令引用:name=COMMAND 或者 name=$(COMMAND)
  • 注意:变量赋值是临时生效,当退出终端后,变量会自动删除,无法持久保存,脚本中的变量会随着脚本结束,也会自动删除

变量引用:

  • $name
  • ${name}

弱引用和强引用

  • "$name " 弱引用,其中的变量引用会被替换为变量值
  • '$name ' 强引用,其中的变量引用不会被替换为变量值,而保持原字符串
[root@localhost opt]# producet=kgc
[root@localhost opt]# echo $producet 
kgc
[root@localhost opt]# version=6.0
[root@localhost opt]# echo $producet$version
kgc6.0
[root@localhost opt]# echo "$producet$version"
kgc6.0
[root@localhost opt]# echo '$producet$version'
$producet$version
[root@localhost opt]# echo $producet6.0
.0
[root@localhost opt]# echo ${producet}6.0
kgc6.0
[root@localhost opt]# echo ${producet}$version
kgc6.0

{ }是用来控制变量名范围的

变量追加值

格式 变量名+=追加值

[root@centos8 ~]#TITLE=CTO
[root@centos8 ~]#TITLE+=:wang
[root@centos8 ~]#echo $TITLE
CTO:wang

[root@centos8 ~]PATH+=:/mnt
[root@centos8 ~]PATH+=/data

总结:

1.赋值时使用双引号(" ")可以直接调用变量

2.赋值时使用单引号(' ')只会被认为是字符 不会调用变量

3.赋值时使用(``反撇在tab上面)命令替换,提取命令执行后的输出结 果 和$( ) 用法相同

4.{}可以分隔变量值

3.3 read -p

从键盘输入的内容变成变量

[root@localhost opt]# read -p "现在的时间是" time
现在的时间是9[root@localhost opt]# echo $time
9

image.png

3.4整数的运算

expr和let只能进行整数的运算

格式: expr 变量1 运算符 变量2 [运算符 变量3]

运算符:

加法 +

减法 -

乘法 \ *

除法 /

取余 (取模)%

#let
[root@localhost ~]#a=1
[root@localhost ~]#b=2
[root@localhost ~]#let z=a+b
[root@localhost ~]#echo $z
3
[root@localhost ~]#let z=$[a-b]
[root@localhost ~]#echo $z
-1
[root@localhost ~]#let z=$((a-b))
[root@localhost ~]#echo $z
-1

image.png

#expr
[root@localhost ~]#a=1
[root@localhost ~]#b=2
[root@localhost ~]#expr $a + $b
3
#加减乘除前后有空格

随机数生成器:

[root@localhost ~]# echo $[RANDOM%34+1]

提取系统信息

#!/bin/bash
ip=$(ifconfig ens33|grep netmask|tr -s ' ' |cut -d ' ' -f3)
mem=$(free -h|grep Mem|tr -s ' '|cut -d ' ' -f2)
hostname=$(hostname)
nh=`uname -r`
disk=$(lsblk|grep disk|tr -s ' ' |cut -d' ' -f4)
cpuxh=$(lscpu |grep '型号:'|tr -s ' ' |cut -d' ' -f2)
cpuhs=$(lscpu |grep 'CPU(s):'|tr -s ' ' |cut -d' ' -f2)





echo "该主机的ip地址是:  $ip"
echo "该主机的总内存是:  $mem"
echo "该主机的主机名是:  $hostname"
echo "该主机的内核版本是:$nh"
echo "该主机的disk大小为:$disk"
echo "该主机的cpu型号:   $cpuxh"
echo "该主机的cpu核数:   $cpuhs

image.png

3.5 环境变量

  1. 由系统提前创建,用来设置用户的工作环境
  2. 可以使用env查看环境变量
  3. 需要记住的常用环境变量

常用的有

$USER 表示用户名称

$HOME 表示用户的宿主目录

$LANG 表示语言和字符集

$PWD 表示当前所在工作目录

$PATH 表示可执行用户程序的默认路径

环境变量的全局配置文件:

/etc/profile如果修改此文件会作用于所有用户

~/.bash_profile 用户独立的配置文件,修改这个文件只作用于当前用户 可以用来长期变更或设置环境变量

3.6位置变量

[root@test1 ~]# vim 1.sh      
#!/bin/bash
echo "$1"            位置1
echo "$2"            位置2
echo "${10}"         位置10
echo "$10"           位置1和0
echo "$*"            将所有项当成一个值
echo "$@"            所有项
echo "$0"            脚本自身
echo "$#"            后面参数的个数
[root@test1 ~]# ./1.sh {1..10}
1 
2
10
10
1 2 3 4 5 6 7 8 9 10



$0 表示当前的脚本名称

[root@test1 ~]# vim weizhi.sh
#!/bin/bash
sum=`expr $1 + $2`
echo "$1+$2=$sum"
[root@test1 ~]# chmod +x weizhi.sh
[root@test1 ~]# ./weizhi.sh 12 34 56
12+34=46
[root@test1 ~]#cat qiuhe.sh
#!/bin/bash
i=$1
m=$2
sum=0
let sum=$[i+m]
echo $sum

3.7预定义(状态)变量

系统已经设置好了,直接可以拿来使用,不需要知道为什么,自己死记硬背

  • $*:表示所有位置参数的内容看成一个整体返回 返回所有
  • $@:表示所有位置参数的内容分割成n份,每份作为一个独立的个体返回 返回所有
  • $?:表示前一条命令执行后的返回状态,返回值为 0 表示执行正确,返回任何非 0值均表示执行出现异常
  • $#:表示命令行中位置参数的总个数
  • $0:表示当前执行的脚本或程序的名称 当前脚本的名字
  • '$$':当前进程id
  • $!: 后台任务最后一个id

$*是将整个参数名看做一个整体

$@是把每一个参数看成一个整体

4.条件语句

4.1测试

test测试文件的表达式是否成立

格式1:test 条件表达式

格式2:[ 注意两边需要空格 ]

格式3:[ 操作符 文件或者目录]

操作符:

-d:测试是否为目录(Directory)
-e:测试目录或文件是否存在(Exist)
-a:测试目录或文件是否存在(Exist)
-f:测试是否为文件(File)
-r:测试当前用户是否有权限读取(Read)
-w:测试当前用户是否有权限写入(Write)
-x:测试当前用户是否有权限执行(eXcute)
-L: 测试是否为软连接文件

属性测试补充:
-s FILE #是否存在且非空
-t fd #fd 文件描述符是否在某终端已经打开
-N FILE #文件自从上一次被读取之后是否被修改过
-O FILE #当前有效用户是否为文件属主
-G FILE #当前有效用户是否为文件属组

若真,则状态码变量 $? 返回0

若假,则状态码变量 $? 返回1

条件测试命令

image.png

image.png

4.2 比较整数数值

格式:[ 整数1 操作符 整数2 ] 公式

 -eq:第一个数等于(Equal)第二个数
 -ne:第一个数不等于(Not Equal)第二个数
 -gt:第一个数大于(Greater Than)第二个数
 -lt:第一个数小于(Lesser Than)第二个数
 -le:第一个数小于或等于(Lesser or Equal)第二个数
 -ge:第一个数大于或等于(Greater or Equal)第二个数
 
[root@test1 ~]# a=2        实例
[root@test1 ~]# b=3
[root@test1 ~] [ $a -eq $b ]
[root@test1 ~]# echo $?
1
[root@test1 ~]# [ 2 -le 3 ]
[root@test1 ~]# echo $?
0

image.png

4.3 字符串比较

常见的测试操作符

  • =:字符串内容相同
  • !=:字符串内容不同,! 号表示相反的意思
  • -z:字符串内容为空
  • -n: 字符是否存在

格式:

[ 字符串1 = 字符串2 ] 是否相同

[ 字符串1 != 字符串2 ] 是否不相同

[ -z 字符串 ] 是否为空

[ -n 字符串 ] 字符是否存在

[root@localhost data]#str1=wang
[root@localhost data]#str2=zhou
[root@localhost data]#[ $str1 = $str2 ]
[root@localhost data]#echo $?
1

[root@localhost etc]# [ $USER = root ]&& echo true
true

image.png

4.4 逻辑测试

格式1:[ 表达式1 ] 操作符 [ 表达式2 ] ...

格式2:命令1 操作符 命令2 ...

常见条件

  • -a或&&:逻辑与,“而且”的意思全真才为真
  • -o或||:逻辑或,“或者”的意思一真即为真
  • !:逻辑否

第一种形式

CMD1 短路与 CMD2      &&   同时满足命令1 和命令2 的要求  才会返回正确
全真才为真  一假即为假      
第一个CMD1结果为真 ,第二个CMD2必须要参与运算,才能得到最终的结果 
第一个CMD1结果为假 ,总的结果必定为假,因此不需要执行CMD2

第二种形式

CMD1 短路或 CMD2
一真即为真
第一个CMD1结果为真 (1),总的结果必定为1,因此不需要执行CMD2
第一个CMD1结果为假 (0),第二个CMD2 必须要参与运算,才能得到最终的结果

image.png

第一种形式例子:

image.png

第二种形式例子:

ping -c 3 -i 0.5 -W2 $1 &> /dev/null && echo "$1 online" || echo "$1 off"

image.png

image.png

4.5双中括号

[[ expression ]] 用法
== 左侧字符串是否和右侧的PATTERN相同
 注意:此表达式用于[[ ]]中,PATTERN为通配符
=~ 左侧字符串是否能够被右侧的正则表达式的PATTERN所匹配
 注意: 此表达式用于[[ ]]中;扩展的正则表达式

例子:

#通配符
[root@centos8 ~]#FILE=test.log
[root@centos8 ~]#[[ "$FILE" == *.log ]]   判断是否匹配
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#FILE=test.txt
[root@centos8 ~]#[[ "$FILE" == *.log ]]
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#[[ "$FILE" != *.log ]]
[root@centos8 ~]#echo $?
0

image.png

4.6 () { }

格式:

(空格CMD1;CMD2;...空格)和 {空格CMD1;CMD2;...;空格} 都可以将多个命令组合在一起,批量执行

[root@localhost opt]#( cd /data;pwd   )
/data
[root@localhost opt]#{ cd /data;ls;  }
1.sh  all.log  fwyum.sh  khyum.sh  text.sh

#()会开启子shell

#{}不会开启子shell

image.png

4.6if语句结构

4.6.1单分支结构

单分支

if 判断条件;

then   条件为真的分支代码

fi

image.png

4.6.2 双分支

双分支

if 判断条件; 

then
 条件为真的分支代码

else
 条件为假的分支代码

fi

image.png

执行脚本

image.png

4.6.3 多分支

if 判断条件1
then
 条件1为真的分支代码

elif 判断条件2
then
 条件2为真的分支代码

elif 判断条件3
 条件3为真的分支代码
then
...
else
 以上条件都为假的分支代码

fi

image.png

4.7 case结构

格式:

case WORD in [PATTERN [| PATTERN]...) COMMANDS ;;]... esac

case 变量引用 in
PAT1)              
 分支1
 ;;
PAT2)
 分支2
 ;;
...
*)                //其他,必须要有的格式
 默认分支
 ;;

case支持glob风格的通配符:
* 任意长度任意字符
? 任意单个字符
[0-9] 指定范围内的任意单个字符
|   或者,如: a|b

image.png

4.8 echo

echo 命令

echo -n :表示不换行输出

echo -e :表示输出转义符

常用的转义符

选项作用
\r光标移至行首,并且不换行
\s当前shell的名称,如bash
\t插入Tab键,制表符
\n输出换行
\f换行,但光标仍停留在原处
\表示插入""本身转义
\b表示退格 不显示前一个字符
\c抑制更多的输出或不换行

例子:

image.png

5.正则表达式过滤文本

5.1元字符

元字符(字符匹配): . :匹配任意单个字符,可以是一个汉字

[ ] :匹配指定范围内的任意单个字符,例如[zhou]: zhou中其中一个字符,[0-9] :数字0-9之间任意一个字符

[^ ] :匹配指定范围外的任意单个字符,例如[^zhou]:除了zhou这几个字符以外的单个别的字符,[^a.z]:除了a和z之间还有一个字符不匹配外,匹配其他字符

常用的正则表达式:

[:alnum:] 字母和数字
[:alpha:] 代表任何英文大小写字符,亦即 A-Z, a-z
[:lower:] 小写字母,示例:[[:lower:]],相当于[a-z]
[:upper:] 大写字母
[:blank:] 空白字符(空格和制表符)
[:space:] 包括空格、制表符(水平和垂直)、换行符、回车符等各种类型的空白,比[:blank:]包含的范围广

\w #匹配单词构成部分,等价于[_[:alnum:]]
\W #匹配非单词构成部分,等价于[^_[:alnum:]]
\S     #匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。
\s     #匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。注意
Unicode 正则表达式会匹配全角空格符

例子: 元字符点(.):

[root@localhost ~]#ls /etc/|grep rc[.0-6]
#此处的点代表字符
rc0.d
rc1.d
rc2.d
rc3.d
rc4.d
rc5.d
rc6.d
rc.d
rc.local

image.png

[root@localhost ~]#ls /etc/ | grep 'rc\.'
#点值表示点需要转义
rc.d
rc.local

[root@lzq zyong]#grep r..t /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin


[root@localhost ~]# echo abc |grep a.c              
#表示原来的点需要加\转义
abc
[root@localhost ~]# echo abc |grep a\.c
#不加引号有时匹配会有出入
abc
[root@localhost ~]# echo abc |grep 'a\.c'          
#标准格式需要加'' 或者""

image.png

image.png

[ ]例子:

[root@lzq zyong]#ls  |grep '[zhou].txt'
#匹配[]中任意一个字符
h.txt
o.txt
u.txt
z.txt


[root@localhost ~]# ls [a-d].txt                
#通配符
a.txt  A.txt  b.txt  B.txt  c.txt  C.txt  d.txt
[root@localhost ~]# ls |grep '[a-d].txt'             
#真正的小写在正则表达式中
a.txt
b.txt
c.txt
d.txt

image.png

[^ ]例子:

[root@localhost ~]#ls
anaconda-ks.cfg  b.txt  d.txt  initial-setup-ks.cfg  模板  图片  下载  桌面
a.txt            c.txt  f.txt  公共                  视频  文档  音乐
[root@localhost ~]#ls |grep '[^a-c].txt'
d.txt
f.txt

#[]里就是本意不需要转义

注意 ^与[^ ]完全不是一个意思,^是以什么开头的意思,[^]反选的意思

image.png

image.png

5.2 表示次数

* #匹配前面的字符任意次,包括0次,贪婪模式:尽可能长的匹配
.* #任意长度的任意字符,不包括0次
\? #匹配其前面的字符出现0次或1次,即:可有可无
\+ #匹配其前面的字符出现最少1次,即:肯定有且 >=1 次
\{n\} #匹配前面的字符n次
\{m,n\} #匹配前面的字符至少m次,至多n次
\{,n\}  #匹配前面的字符至多n次,<=n
\{n,\}  #匹配前面的字符至少n次

例子:

[root@localhost ~]# echo google |grep 'go\{2\}gle'
#带表前面的o出现2次
google
[root@localhost ~]# echo gooooogle |grep 'go\{2,\}gle'  
#带表前面的o出现2次以上
gooooogle
[root@localhost ~]# echo gooooogle |grep 'go\{2,5\}gle'
#带表前面的o出现2次以上5次以下
gooooogle
[root@localhost ~]# echo goooooogle |grep 'go\{2,5\}gle'
[root@localhost ~]# 
[root@localhost ~]# echo goooooogle |grep 'go*gle'    
#表示0次到任意次
goooooogle
[root@localhost ~]# echo ggle |grep "go*gle"
ggle
[root@localhost ~]# echo gggle |grep "go*gle"    
#grep 包含最前面的g不匹配
gggle
[root@localhost ~]# echo gdadadadgle |grep "g.*gle"    
#.*代表任意匹配所有
gdadadadgle
[root@localhost ~]# echo ggle |grep "go\?gle"      
# \?一次或者0次
ggle
[root@localhost ~]# echo gogle |grep "go\?gle"
gogle
[root@[root@localhost ~]# echo google |grep "go\+gle"   
#一个以上
google
[root@localhost ~]# echo gogle |grep "go\+gle"
gogle
[root@localhost ~]# echo ggle |grep "go\+gle"
[root@localhost ~]# echo google |grep "go\?gle"

image.png

image.png

5.3位置锚定

^ #行首锚定, 用于模式的最左侧
$ #行尾锚定,用于模式的最右侧
^PATTERN$ #用于模式匹配整行 (单独一行  只有root)
^$ #空行
^[[:space:]]*$ #  空白行


\< 或 \b        #词首锚定,用于单词模式的左侧(连续的数字,字母,下划线都算单词内部)
\> 或 \b        #词尾锚定,用于单词模式的右侧
\<PATTERN\>     #匹配整个单词

例子:

[root@localhost ~]#grep "^[^#]" /etc/fstab

#匹配不是#号开头的内容

[root@localhost data]#grep "^google$" test.txt
#只匹配google 这个字符

[root@localhost ~]#grep "^[[:space:]]*$" /etc/fstab

[root@localhost ~]#echo hello-123 |grep "\<123"
#除了 字母 数字 下划线其他都算 单词的分隔符
hello-123
[root@localhost ~]#echo hello 123 |grep "\<123"
hello 123

image.png

image.png

5.4 分组或其他

分组:

() 将多个字符捆绑在一起,当作一个整体处理,如:(root)+

后向引用:分组括号中的模式匹配到的内容会被正则表达式引擎记录于内部的变量中,这些变量的命名

方式为: \1, \2, \3, ...

\1 表示从左侧起第一个左括号以及与之匹配右括号之间的模式所匹配到的字符

或者:

或者
或者:\|

例子:

[root@localhost ~]#echo abcabcabc |grep "\(abc\)\{3\}"
#分组 匹配abc
abcabcabc
[root@localhost ~]#echo 1abc |grep  "1\|2abc"
#只匹配了1
1abc

[root@localhost ~]#echo 1abc |grep  "\(1\|2\)abc"
#1abc或者2abc
1abc

[root@localhost ~]#ifconfig ens33|grep netmask|grep -o '\([0-9]\{1,3\}\.\)\{3\}[0-9]\{3\}'|head -1
192.168.91.100

[root@localhost ~] ens33 |grep netmask|grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}'|head -1


[root@localhost ky15]#ifconfig ens33 |grep netmask|grep -Eo '([0-9]{1,3}.){4}'

image.png

image.png

5.5 扩展正则表达式(表示字符相差不大)

表示次数:

*   匹配前面字符任意次
? 0或1次
+ 1次或多次
{n} 匹配n次
{m,n} 至少m,至多n次
{,n}  #匹配前面的字符至多n次,<=n,n可以为0
{n,} #匹配前面的字符至少n次,<=n,n可以为0

表示分组:

() 分组
分组:() 将多个字符捆绑在一起,当作一个整体处理,如:\(root\)+
后向引用:\1, \2, ...
| 或者  
a|b #ab
C|cat #Ccat
(C|c)at #Catcat

其实就是grep 加上-E选项后,不需要加反斜杠了,已经表示过转义了

练习:

表示qq号:
[root@localhost ~]#echo "aa940132245" |grep "\b[0-9]\{6,12\}\b"

表示邮箱
echo "zhou@qq.com" |grep -E "[[:alnum:]_]+@[[:alnum:]_]+\.[[:alnum:]_]+"

表示手机号
echo "13705173391"|grep -E "\b1[3456789][0-9]{9}\b"

image.png

5.6 grep

格式: grep [选项]... 查找条件 目标文件

选项:

-i:查找时忽略大小写

-v:反向查找,输出与查找条件不相符的行
 grep -Ev '^[[:space:]]*#|^$' /etc/fstab

-o 只显示匹配项

-f 对比两个文件的相同行

-c 匹配的行数
 [root@localhost ky15]# grep -c root passwd 2
 
 -color=auto #对匹配到的文本着色显示

-m  # 匹配#次后停止
 grep -m 1 root /etc/passwd   #多个匹配只取第一个

-n 显示匹配的行号

-q 静默模式,不输出任何信息

-A # after, 后#行 
grep -A3 root /etc/passwd   #匹配到的行后3行业显示出来

-B # before, 前#行

-C # context, 前后各#行

-e 实现多个选项间的逻辑or关系,如:grep –e ‘cat ' -e ‘dog' file
grep -e root -e bash /etc/passwd #包含root或者包含bash 的行

-w 匹配整个单词

-E 使用ERE,相当于egrep

-F 不支持正则表达式,相当于fgrep

-f   file 根据模式文件,处理两个文件相同内容 把第一个文件作为匹配条件

-r   递归目录,但不处理软链接

-R   递归目录,但处理软链接

例子:

[root@test1 opt]# cat 123.txt |grep -v '^$' >test.txt  //将非空行写入到test.txt文件
[root@test1 opt]# grep "^b" 123.txt    //过滤已b开头
[root@test1 opt]#grep '/$'  123.txt    //过滤已/结尾
[root@test1 opt]# grep -v "^$" 123.txt //过滤非空行3 备份与

[root@localhost yum.repos.d]# ifconfig ens33 |grep -o "[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+"
192.168.91.100
255.255.255.0
192.168.91.255
[root@localhost yum.repos.d]# ifconfig ens33 |grep -o "[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+"|head -1
192.168.91.100

提高题:
### 统计当前主机的连接状态
[root@localhost ~]# ss -nta | grep -v '^State' |cut -d" " -f1|sort |uniq -c
      3 ESTAB
     17 LISTEN
####统计当前连接主机数
[root@localhost ~]#ss -nt |tr -s " "|cut -d " " -f5|cut -d ":" -f1 |sort|uniq -c
      3 192.168.91.1
      1 192.168.91.101
      1 Address

6.AWK

awk:Aho, Weinberger, Kernighan,报告生成器,格式化文本输出,GNU/Linux发布的AWK目前由自

由软件基金会(FSF)进行开发和维护,通常也称它为 GNU AWK

有多种版本:

AWK:原先来源于 AT & T 实验室的的AWK

NAWK:New awk,AT & T 实验室的AWK的升级版

6.1 AWK的原理

image.png

第一步:执行BEGIN{action;… }语句块中的语句
第二步:从文件或标准输入(stdin)读取一行,然后执行pattern{ action;… }语句块,它逐行扫描文件,
从第一行到最后一行重复这个过程,直到文件全部被读取完毕。
第三步:当读至输入流末尾时,执行END{action;…}语句块
BEGIN语句块在awk开始从输入流中读取行之前被执行,这是一个可选的语句块,比如变量初始化、打印输出表格的表头等语句通常可以写在BEGIN语句块中
END语句块在awk从输入流中读取完所有的行之后即被执行,比如打印所有行的分析结果这类信息汇总都是在END语句块中完成,它也是一个可选语句块
pattern语句块中的通用命令是最重要的部分,也是可选的。如果没有提供pattern语句块,则默认执行{ print },即打印每一个读取到的行,awk读取的每一行都会执行该语句块

awk 比较倾向于将一行分成多个“字段”然后再进行处理,且默认情况下字段的分隔符为空格或 tab 键。awk 执行结果可以通过 print 的功能将字段数据打印显示。

格式: awk 选项 模式 处理的动作 选项:

-F :指定分隔符

-V :自定义变量

-f :脚本

6.2 基础用法

print动作

[root@localhost ~]#awk '{print}' 
##在打印一遍
dd
dd

[root@localhost ~]#awk '{print "hello"}' 
#字符串需要添加双引号,单引号已被使用
1
hello
1
hello

##############BEGIN  ###################
[root@localhost ky15]#awk 'BEGIN {print "hello"}'
#BEGIN比较特殊值打一行   pattern
hello
[root@localhost ~]#awk -F: 'BEGIN {print "hello"} {print $1}' /etc/passwd |head -n3
#先处理BEGIN 中的式子
hello
root
bin

image.png

[root@localhost ky15]#cat /etc/passwd|awk -F: '{print $1,$3}'
#指定冒号作为分隔符,打印第一列和第三列
[root@localhost ky15]#cat /etc/passwd|awk -F: '{print $1":"$3}'
#用冒号分隔开
[root@localhost ~]#df|awk -F"( +|%)" '{print $5}'
[root@localhost ky15]#df |awk -F"[[:space:]]+|%" '{print $5}'
[root@localhost ky15]#df |awk -F"[ %]+" '{print $5}'

image.png

[root@localhost ~]#awk -F: '{print $0}' /etc/passwd
#$0代表全部元素
[root@localhost ~]#awk -F: '{print $1}' /etc/passwd
#代表第一列
[root@localhost ~]#awk -F: '{print $1,$3}' /etc/passwd
#代表第一第三列
[root@localhost ky15]#awk '/^root/{print}' passwd 
#已root为开头的行   跟vim末行模式下s///查找意思一样
[root@localhost ky15]#grep -c "/bin/bash$" passwd 
#统计当前已/bin/bash结尾的行

image.png

6.3awk常见的内置变量

  • FS :指定每行文本的字段分隔符,缺省为空格或制表符(tab)。与 “-F”作用相同 -v "FS=:"
  • OFS:输出时的分隔符
  • NF:当前处理的行的字段个数
  • NR:当前处理的行的行号(序数)
  • $0:当前处理的行的整行内容
  • $n:当前处理行的第n个字段(第n列)
  • FILENAME:被处理的文件名
  • RS:行分隔符。awk从文件上读取资料时,将根据RS的定义就把资料切割成许多条记录,而awk一次仅读入一条记录进行处理。预设值是\n

FS:

[root@localhost ky15]#awk -v FS=':' '{print $1FS$3}' /etc/passwd
#此处FS 相当于于变量  -v 变量赋值  相当于 指定: 为分隔符  
[root@localhost ky15]#awk -F: '{print $1":"$3}' /etc/passwd

shell中的变量
[root@localhost ky15]#fs=":";awk -v FS=$fs '{print $1FS$3}' /etc/passwd
#定义变量传给FS


#########   支持变量    ##################
[root@localhost ky15]#fs=":";awk -v FS=$fs -v OFS="+" '{print $1,$3}' /etc/passwd
#输出分隔符

-F  -FS一起使用  -F 的优先级高

image.png

OFS:

[root@localhost ~]#awk -v FS=':' -v OFS='==' '{print $1,$3}' /etc/passwd
root==0
bin==1
daemon==2
adm==3
lp==4
sync==5

image.png

RS:

默认是已 /n (换行符)为一条记录的分隔符
不动他
[root@localhost ~]#echo $PATH | awk -v RS=':' '{print $0}'
/usr/local/sbin
/usr/local/bin
/usr/sbin
/usr/bin
/root/bin

image.png

NF:

代表字段的个数
[root@localhost ky15]#awk -F: '{print NF}' /etc/passwd

[root@localhost ky15]#awk -F: '{print $NF}' /etc/passwd
#$NF最后一个字段

[root@localhost ky15]#df|awk -F: '{print $(NF-1)}'
#倒数第二行
[root@localhost ky15]#df|awk -F "[ %]+" '{print $(NF-1)}'

image.png

image.png

NR:

行号
[root@localhost ky15]#awk '{print $1,NR}' /etc/passwd
##行号
[root@localhost ky15]#awk 'NR==2{print $1}' /etc/passwd
#只取第二行的第一个字段  可以和fs搭配使用
[root@localhost ky15]#awk 'NR==1,NR==3{print}' passwd 
#打印出1到3 行
[root@localhost ky15]#awk 'NR==1||NR==3{print}' passwd
#打印出1和3行

image.png

6.4 模式

格式: awk '模式{处理动作}'

不支持使用行号,但是可以使用变量NR 间接指定行号

/pat1/   
# 匹配pat1 的行

/pat1/,/pat2/ 
#正则表达式1   到正则表达式2  之间的行       如果匹配不到2的表达式  会一直匹配到文末

例子 :
[root@lzz /]#cat /etc/passwd |awk -F: '/^root/,/^bin/{print$0}'
rootec:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
#使用正则表达式

image.png

#####逻辑
与:&&,并且关系
或:||,或者关系
非:!,取反

例子
[root@localhost ~]#seq 10 |awk 'NR>=3 && NR<=6'
3
4
5
6
[root@localhost ~]#awk 'NR>=3 && NR<=6{print NR,$0}' /etc/passwd
#表示第三行到第六行,显示全行
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
6 sync:x:5:0:sync:/sbin:/bin/sync
awk -F:  '$3>=100 && $3<=1000{print $1}' /etc/passwd
#表示第三列大于100小于1000的行,打印第一列

6.5条件判断

if语句:awk的if语句也分为单分支、双分支和多分支
单分支为if(){}
双分支为if(){}else{}
多分支为if(){}else if(){}else{}



#写在动作里

[root@localhost ~]#awk -F: '{if($3>1000)print $1,$3}' /etc/passwd
#如果第三列大于1000则打印第一列与第三列
nfsnobody 65534
mysql 1001
lisi 1002
liwu 1003


[root@localhost ~]#awk -F: '{if($3>1000){print $1,$3}else{print $3}}' /etc/passwd
#如果第三列大于1000则打印第一和第三列,其他只打印第三列

image.png

6.6 for

awk 'BEGIN{sum=0;for(i=1;i<=100;i++){sum+=i};print sum}'
5050

#相当于在awk里面直接做出100个数相加
在awk中做计算
[root@localhost ~]# awk 'BEGIN{x=10;print x}'  //如果不用引号awk就当作一个变量来输出了,所以不需要加$了
10
[root@localhost ~]# awk 'BEGIN{x=10;print x+1}'   //BEGIN在处理文件之前,所以后面不跟文件名也不影响
11
[root@localhost ~]# awk 'BEGIN{x=10;x++;print x}'
11
[root@localhost ~]# awk 'BEGIN{print x+1}'    //不指定初始值,初始值就为0,如果是字符串,则默认为空
1
[root@localhost ~]# awk 'BEGIN{print 2.5+3.5}'   //小数也可以运算
6
[root@localhost ~]# awk 'BEGIN{print 2-1}'
1
[root@localhost ~]# awk 'BEGIN{print 3*4}'
12
[root@localhost ~]# awk 'BEGIN{print 3**2}'
9