grep ||sed||awk
Grep命令:
grep语法格式:
grep [option] [pattern] [file1,file2...]
必须掌握的选项:
-v 显示不匹配pattern的行
-i 搜索时忽略大小写
-n 显示行号
-E 支持扩展的正则表达式
-F 不支持正则表达式,按字符串的字面意思进行匹配
-r 递归搜索
需了解的选项:
-c 只输出匹配行的数量,不显示具体内容
-w 匹配整词
-x 匹配整行
-l 只列出匹配的文件名,不显示具体匹配行内容
grep和egrep区别:
grep默认不支持扩展正则表达式,只支持基础正则表达式
使用grep -E可以支持扩展正则表达式
使用egrep可以支持扩展正则表达式,与grep -E等价
举例:
查看不包括nologin的字符串,并显示行号
[root@ansible fang]# grep -nv "nologin" /etc/passwd
1:root:x:0:0:root:/root:/bin/bash
6:sync:x:5:0:sync:/sbin:/bin/sync
7:shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
8:halt:x:7:0:halt:/sbin:/sbin/halt
43:fangqiming:x:1000:1000:fangqiming:/home/fangqiming:/bin/bash
[root@ansible fang]#
重点:
[pattern]正则表达式的使用
Sed命令:
sed语法(查询,删除,增加):
举例:
sed -n '/192.*/p' dd.yml
功能:将dd.yml文件中的包含192.的行打印出来,值打印匹配的行
sed –i ‘s/love/like/g’ sed.txt
功能:将sed.txt中所有love替换为like
将list.txt文件中的内容插入到匹配到的行后面
sed –i ‘/root/r list’ password
将sed匹配到的行内容写入到文件中
sed ‘/\/bin\/bash/w /tmp/user_login.txt’ passwd
将匹配到的内容对源文件进行替换为大写
Sed –i ‘s/\/bin\/bash/ \/BIN\/BASH/g’ passwd
将匹配到的内容,对源文件进行大写的修改,并且同一行内只替换前两个
Sed –i ‘s/root/ROOT/2g’ passwd
想匹配到的内容只显示行号
Sed –n ‘/\/sbin\/nologin/=’ passwd
其他编辑命令
其他的编辑命令
= 显示行号
反向引用:
&和\1 引用模式匹配到的整个串
Sed “s/1..e/&r/g” file 在file中搜寻以1开头,然后跟两个任意字符,以e结尾的字符串,用&代替搜寻到的字符串增加r字符后,对file进行修改
Sed “s/\(1..e\)/\1r/g” file 和上一条命令实现同样的功能,\1代表搜寻到的字符串
注意: \1使用()对匹配到的字符串进行引用,如果只是想要替换匹配到的字符串的一部分,必须使用\1这种方式进行引用替换
反向引用
将正则匹配到的had..p的内容替换为had..ps &表示引用前面整个字符串
将所有匹配到的had..p 后面家s
sed –i ‘s/had..p/&s/g’ str.txt
1也表示引用前面第一个()中的字符串,相对&更加灵活
sed –i ‘s/\(had..p\)/\1O/g’ str.txt
sed "s/\(l..e\)/\1r/g" file 和上面实现一样的功能,使用\1代表搜寻到的字符串
在脚本中使用sed注意事项
- 匹配模式中存在变量,则建议使用双引号
- Sed中需要引入自定义变量时,如果外面使用单引号,则自定义变量也必须使用单引号
引用变量的方式一
[root@ansible fang]# cat shell.sh
#!/bin/bash
#
old_str=fangqiming
new_str=FangQiMing
file="$1"
sed -i "s/$old_str/$new_str/g" $file
[root@ansible fang]# bash shell.sh 1.txt 执行
引用变量的方式二
#!/bin/bash
old_str=fangqiming
new_str=FangQiMing
file="$1"
sed -i 's/'$old_str'/'$new_str'/g' $file
这是在脚本中修改脚本内容的快捷方法
其实只是做的演示,如此简单的功能,我们在脚本中就可以实现拉,
当前行到最后一行,将所有的HADOOP替换为hadoop
:.,$s/Fang/fang/g
举例:
需求描述: 处理一个类似MYSQL配置文件my.cnf的文本,示例如下;
编写脚本实现以下功能:输出文件有几段,并且针对每个段可以统计配置参数总个个数
=====================
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
# Settings user and group are ignored when systemd is used.
# If you need to run mysqld under a different user or group,
# customize your systemd unit file for mariadb according to the
# instructions in http://fedoraproject.org/wiki/Systemd
[mysqld_safe]
log-error=/var/log/mariadb/mariadb.log
pid-file=/var/run/mariadb/mariadb.pid
输出是这样的格式
[root@ansible test]# bash mysql_client.sh
1: mysqld 3
2: mysqld_safe 4
技术要点:
首先,过滤标题的信息,去掉左右的中括号
[root@ansible test]# sed -n '/\[*\]/p' my.cnf | sed -e 's/\[//g' -e 's/\]//g'
mysqld
mysqld_safe
[root@ansible test]#
其次,按照标题信息,取出每个标题之间的信息,过滤掉空行的数据,过滤掉注释的行数据,过滤掉标题行的数据,最终的实现是如下的样子
[root@ansible test]# sed -n '/\[mysqld\]/,/\[.*\]/p' my.cnf | grep -v "^$" | grep -v "#" | grep -v "\[.*\]"
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
symbolic-links=0
[root@ansible test]#
再次,对过滤完成的数据进行循环统计个数,最后组合成想要的数据就好了
实现代码如下:
[root@ansible test]# cat mysql_client.sh
#!/bin/bash
#
DIR_NAME=/etc/ansible/fang/test/my.cnf
function output_line
{
echo "`sed -n '/\[.*\]/p' $DIR_NAME | sed -e 's/\[//g' -e 's/\]//g'`"
}
function output_line_items
{
index=0
items=`sed -n '/\['$1'\]/,/\[.*\]/p' $DIR_NAME | grep -v "^$" | grep -v "#" | grep -v "\[.*\]"`
for item in $items
do
index=`expr $index + 1`
done
echo $index
}
number=0
for out in `output_line`
do
number=`expr $number + 1`
items_count=`output_line_items $out`
echo "$number: $out $items_count"
done
[root@ansible test]#
删除操作,是不推荐的,因为匹配删除后,会继续进行下面的匹配,和预期结果是不一致的,匹配和行数颠倒以下,可以进行匹配,如下
Sed –i ‘/\/sbin\/nologin/,13d’ passwd 这种不推荐
Sed –i ‘13,/ \/sbin\/nologin /d’ passwd这种可以
练习题:
删除/etc/passwd中德尔第15行
sed –i ‘15d’ /etc/passwd
删除/etc/passwd中的第8行到第14行的所有内容
sed –i ‘8,14d’ /etc/passwd
删除/etc/passwd中的不能登录的用户(筛选条件: /sbin/nologin)
sed –i ‘/\/sbin\/nologin/d’ /etc/passwd
删除/etc/passwd中以mail开头的行,到以yarn开头的行的所有内容
sed –i ‘/^mail/,/^yarn/d’ /etc/passwd
删除/etc/passwd中以yarn开头的行到最后行的所有内容
sed –i ‘/^yarn/,$’ /etc/passwd
以#开头的注释删除掉,其中#号之前的空格也需要匹配[:blank:]表示空格
sed –i ‘/[:blank:]*#/d’ nginx.conf
在配置文件中所有不以#开头的行前面添加*符号,注意: 以#开头的行不添加
sed –i ‘s/[^#]/\*&/g’ nginx.cnf
sed语法(修改):
sed命令 匹配方式 /pattern1/s/old/new/
[root@ansible test]# sed -i '/socket=/s/socket/sockets/g' my.cnf
[root@ansible test]# cat my.cnf
[mysqld]
datadir=/var/lib/mysql
sockets=/var/lib/mysql/mysql.sock
练习题:
1、修改/etc/passwd中第1行中第1个root为ROOT
sed -i '1s/root/ROOT/' passwd
2、修改/etc/passwd中第5行到第10行中所有的/sbin/nologin为/bin/bash
sed -i '5,10s/\/sbin\/nologin/\/bin\/bash/g' passwd
3、修改/etc/passwd中匹配到/sbin/nologin的行,将匹配到行中的login改为大写的LOGIN
sed -i '/\/sbin\/nologin/s/login/LOGIN/g' passwd
4、修改/etc/passwd中从匹配到以root开头的行,到匹配到行中包含mail的所有行。修改内为将这些所有匹配到的行中的bin改为HADOOP
sed -i '/^root/,/mail/s/bin/HADOOP/g' passwd
5、修改/etc/passwd中从匹配到以root开头的行,到第15行中的所有行,修改内容为将这些行中的nologin修改为SPARK
sed -i '/^root/,15s/nologin/SPARK/g' passwd
6、修改/etc/passwd中从第15行开始,到匹配到以yarn开头的所有航,修改内容为将这些行中的bin换位BIN
sed -i '15,/^yarn/s/bin/BIN/g' passwd
sed语法(修改)匹配的行后面追加
1、a 在匹配行后面追加
2、i 在匹配行前面追加
3、r 将文件内容追加到匹配行后面
4、w 将匹配行写入指定文件
示例:
追加用法示例详解:
1、a append
(1)、passwd文件第10行后面追加"Add Line Behind"
sed -i '10a Add Line Begind' passwd
(2)、passwd文件第10行到第20行,每一行后面都追加"Test Line Behind"
sed -i '10,20a Test Line Behind' passwd
(3)、passwd文件匹配到/bin/bash的行后面追加"Insert Line For /bin/bash Behind"
sed -i '/\/bin\/bash/a Insert Line For /bin/bash Behind' passwd
2、i
(1)、passwd文件匹配到以yarn开头的行,在匹配航前面追加"Add Line Before"
sed -i '/^yarn/i Add Line Before' passwd
(2)、passwd文件每一行前面都追加"Insert Line Before Every Line"
sed -i 'i Insert Line Before Every Line' passwd
3、r
(1)、将/etc/fstab文件的内容追加到passwd文件的第20行后面
sed -i '20r /etc/fstab' passwd
(2)、将/etc/inittab文件内容追加到passwd文件匹配/bin/bash行的后面
sed -i '/\/bin\/bash/r /etc/inittab' passwd
(3)、将/etc/vconsole.conf文件内容追加到passwd文件中特定行后面,匹配以ftp开头的行,到第18行的所有行
sed -i '//,18r /etc/vconsole.conf' passwd
4、w
(1)、将passwd文件匹配到/bin/bash的行追加到/tmp/sed.txt文件中
sed -i '/\/bin\/bash/w /tmp/sed.txt' passwd
(2)、将passwd文件从第10行开始,到匹配到hdfs开头的所有行内容追加到/tmp/sed-1.txt
sed -i '10,/^hdfs/w /tmp/sed-1.txt' passwd
匹配到行之前插入
Awk命令:
命令的格式:
Awk ‘BEGIN{}PATTERN{command}END{}’ file_name
语法格式 解释
BEGIN{} 正式处理数据之前执行
Pattern 匹配模式
{commands} 处理命令,可以多行
END{} 处理玩所有匹配数据后执行
内置变量:
$0 打印行所有信息
$1~$n 打印行的第1到n个字段的信息
NF Number Field 处理行的字段个数
NR Number Row 处理行的行号
FNR File Number Row多文件处理时,每个文件单独记录行号
FS Field Separator字段分割符,不指定时默认以空格或tab键分割
RS Row Separator 行分隔符,不指定时以回车分割\n
OFS Output Filed Separator 输出字段分隔符。
ORS Output Row Separator 输出行分隔符
FILENAME 处理文件的文件名
ARGC 命令行参数个数
ARGV 命令行参数数组
例如:
输出每行的内容,默认是一个空格或者tab进行分割列
awk ‘{print $0}’ /etc/passwd
行分割 域分割 输出行分割符号
[root@ansible test]# cat 2.txt
xiaoli|xiaoming|xiaohua--fang|qi|ming--ni|shi|shui
[root@ansible test]#
[root@ansible test]# awk 'BEGIN{RS="--"}{print $0}END{}' 2.txt
xiaoli|xiaoming|xiaohua
fang|qi|ming
ni|shi|shui
[root@ansible test]# awk 'BEGIN{RS="--";FS="|";OFS="&"}{print $3}END{}' 2.txt
xiaohua
ming
shui
Printf格式化输出,参数介绍
awk格式化输出之printf总结:
格式符
%s 打印字符串
%d 打印10进制数
%f 打印浮点数
%x 打印16进制数
%o 打印8进制数
%e 打印数字的科学计数法格式
%c 打印单个字符的ASCII码
修饰符
- 左对齐
+ 右对齐
# 显示8进制在前面加0,显示16进制在前面加0x
格式符示例:
1、以字符串格式打印/etc/passwd中的第7个字段,以":"作为分隔符
awk 'BEGIN{FS=":"} {printf "%s",$7}' /etc/passwd
2、以10进制格式打印/etc/passwd中的第3个字段,以":"作为分隔符
awk 'BEGIN{FS=":"} {printf "%d\n",$3}' /etc/passwd
3、以浮点数格式打印/etc/passwd中的第3个字段,以":"作为分隔符
awk 'BEGIN{FS=":"} {printf "%0.3f\n",$3}' /etc/passwd
4、以16进制数格式打印/etc/passwd中的第3个字段,以":"作为分隔符
awk 'BEGIN{FS=":"} {printf "%#x\n",$3}' /etc/passwd
5、以8进制数格式打印/etc/passwd中的第3个字段,以":"作为分隔符
awk 'BEGIN{FS=":"} {printf "%#o\n",$3}' /etc/passwd
6、以科学计数法格式打印/etc/passwd中的第3个字段,以":"作为分隔符
awk 'BEGIN{FS=":"} {printf "%e\n",$3}' /etc/passwd
Awk模式匹配用法:
第一种方法:RegExp
第二种方法:运算符匹配
正则匹配RegExp
匹配/etc/passwd文件行中含有root字符串的所有行
awk 'BEGIN{FS=":"}/root/{print $0}' /etc/passwd
匹配/etc/passwd文件行中以yarn开头的所有行
awk 'BEGIN{FS=":"}/^yarn/{print $0}' /etc/passwd
运算符匹配
关系运算符匹配:
< 小于
> 大于
<= 小于等于
>= 大于等于
== 等于
!= 不等于
~ 匹配正则表达式
!~ 不匹配正则表达式
(1)、以:为分隔符,匹配/etc/passwd文件中第3个字段小于50的所有行信息
awk 'BEGIN{FS=":"}$3<50{print $0}' /etc/passwd
(2)、以:为分隔符,匹配/etc/passwd文件中第3个字段大于50的所有行信息
awk 'BEGIN{FS=":"}$3>50{print $0}' /etc/passwd
(3)、以:为分隔符,匹配/etc/passwd文件中第7个字段为/bin/bash的所有行信息
awk 'BEGIN{FS=":"}$7=="/bin/bash"{print $0}' /etc/passwd
(4)、以:为分隔符,匹配/etc/passwd文件中第7个字段不为/bin/bash的所有行信息
awk 'BEGIN{FS=":"}$7!="/bin/bash"{print $0}' /etc/passwd
(5)、以:为分隔符,匹配/etc/passwd中第3个字段包含3个以上数字的所有行信息
awk 'BEGIN{FS=":"}$3~/[0-9]{3,}/{print $0}' /etc/passwd
布尔运算符匹配
|| 或
&& 与
! 非
(1)、以:为分隔符,匹配/etc/passwd文件中包含hdfs或yarn的所有行信息
awk 'BEGIN{FS=":"}$1=="hdfs" || $1=="yarn" {print $0}' /etc/passwd
(2)、以:为分隔符,匹配/etc/passwd文件中第3个字段小于50并且第4个字段大于50的所有行信息
awk 'BEGIN{FS=":"}$3<50 && $4>50 {print $0}' /etc/passwd
awk动作中的表达式
+ 加
- 减
* 乘
/ 除
% 取模
^或** 乘方
++x 在返回x变量之前,x变量加1
x++ 在返回x变量之后,x变量加1
--x 在返回x变量之前,x变量减1
x-- 在返回x变量之后,x变量减1
1、使用awk计算/etc/services中的空白行数量
awk '/^$/{sum++}END{print sum}' /etc/services
2、计算学生课程分数平均值,学生课程文件内容如下:
Alice 79 80 88 100
xiaoming 88 69 92 99
xiaoli 69 90 99 89
命令如下:
[root@ansible test]# cat student.txt
Alice 79 80 88 100
xiaoming 88 69 92 99
xiaoli 69 90 99 89
[root@ansible test]# awk 'BEGIN{printf "%-8s%-8s%-8s%-8s%-8s%-8s\n","Name","yuwen","math","pysical","English","Average"}{sum=$2+$3+$4+$5;AVG=sum/4;printf "%-8s%-8d%-8d%-8d%-8d%0.2f\n",$1,$2,$3,$4,$5,AVG}' student.txt
Name yuwen math pysical English Average
Alice 79 80 88 100 86.75
xiaoming88 69 92 99 87.00
xiaoli 69 90 99 89 86.75
[root@ansible test]#
条件及循环语句
条件语句:
if(条件表达式1)
动作
else if(条件表达式2)
动作
else
动作
循环语句:
while循环:
while(条件表达式)
动作
do while循环:
do
动作
while(条件表达式)
for循环:
for(初始化计数器;计数器测试;计数器变更)
动作
1、以:为分隔符,只打印/etc/passwd中第3个字段的数值在50-100范围内的行信息
代码:
[root@ansible test]# cat script.awk
BEGIN{
FS=":"
}
{
if($3<50)
{
printf "%-20s%-20s%10d\n","uid>50",$1,$3
}
else if($3>50 && $3<100)
{
printf "%-20s%-20s%10d\n","100>uid>50",$1,$3
}
else
{
printf "%-20s%-20s%10d\n","uid>100",$1,$3
}
}
[root@ansible test]# awk -f script.awk passwd
uid>50 root 0
uid>50 bin 1
uid>50 daemon 2
uid>50 adm 3
uid>50 lp 4
练习: 使用do..while while for 来实现1+2+3….+100的和
字符串函数对照表
length(str) 计算长度
index(str1,str2) 返回在str1中查询到的str2的位置
tolower(str) 小写转换
toupper(str) 大写转换
split(str,arr,fs) 分隔字符串,并保存到数组中
match(str,RE) 返回正则表达式匹配到的子串的位置
substr(str,m,n) 截取子串,从m个字符开始,截取n位。n若不指定,则默认截取到字符串尾
sub(RE,RepStr,str) 替换查找到的第一个子串,在str中搜索符合RE的字符串,将其替换为RepStr;只替换第一个
gsub(RE,RepStr,str) 替换查找到的所有子串,同上,区别替换所有
练习题:
字符串的长度
1、以:为分隔符,返回/etc/passwd中每行中每个字段的长度
root:x:0:0:root:/root:/bin/bash
4:1:1:1:4:5:9
思考:利用到NF内置的变量,处理行的字段个数,每个遍历出来的字段利用函数算出长度打印输出
代码:
[root@ansible test]# cat test.awk
BEGIN{
FS=":"
}
{
i=1
while(i<=NF)
{
if(i==NF)
printf "%d",length($i)
else
printf "%d:",length($i)
i++
}
printf "\n"
}
[root@ansible test]# awk -f test.awk passwd1
4:1:0:0:4:5:9
17
3:1:0:0:3:4:13
6:1:0:0:6:5:13
匹配字符串的位置
搜索字符串"I have a dream"中出现"ea"子串的位置
[root@ansible test]# awk 'BEGIN{string="I hava a dream";aa=match(string,"ea");print aa}'
12
大小写转换
[root@ansible test]# awk 'BEGIN{str="i Want you";print toupper(str);print tolower(str)}'
I WANT YOU
i want you
子字符串的获取
[root@ansible test]# awk 'BEGIN{str="my name is fangqiming";print substr(str,12,19)}'
Fangqiming
字符串的分割
[root@ansible test]# awk 'BEGIN{str="My Name Is FangQiMing";split(str,arr," ");print arr[4]}'
FangQiMing
字符串的替换
[root@ansible test]# awk 'BEGIN{str="My Name Is FangQiMing1988 [email protected]";print gsub(/[0-9]+/,"@secret@",str);print str}'
2
My Name Is FangQiMing@secret@ @secret@@qq.com
[root@ansible test]#
Awk选项总结:
awk中常用选项
-v 定义或引用变量
-f 指定awk命令文件
-F 指定分隔符
-V 查看awk的版本号
[root@ansible test]# awk -v var=$var1 -v ages=$age 'BEGIN{print var,ages}'
fangqiming 32
[root@ansible test]#
指定分隔符
[root@ansible test]# awk -F: '{print $7}' passwd
[root@ansible test]# awk 'BEGIN{FS=":"}{print $7}' passwd
以上两种方式作用相同
[root@ansible test]# awk -V
GNU Awk 4.0.2
数组的使用:
Shell中数组的用法:
array=("Allen" "Mike" "Messi" "Jerry" "Hanmeimei" "Wang")
打印元素: echo ${array[2]}
打印元素个数: echo ${#array[@]}
打印元素长度: echo ${#array[3]}
给元素赋值: array[3]="Li"
删除元素: unset array[2];unset array
分片访问: echo ${array[@]:1:3}
元素内容替换: ${array[@]/e/E} 只替换第一个e;${array[@]//e/E}替换所有的e
数组的遍历:
for a in ${array[@]}
do
echo $a
done
示例如下:
[root@ansible test]# arr=("xiaoli" "hanmeimemi" "lilei" "fang" "zhang")
[root@ansible test]# echo $arr
xiaoli
[root@ansible test]# echo ${arr[@]}
xiaoli hanmeimemi lilei fang zhang
[root@ansible test]# unset arr[0]
[root@ansible test]# echo ${arr[@]}
hanmeimemi lilei fang zhang
[root@ansible test]# for i in ${arr[@]}; do echo $i; done
hanmeimemi
lilei
fang
zhang
[root@ansible test]#
Awk中数组的用法:
在awk中,使用数组时,不仅可以使用1.2..n作为数组下标,也可以使用字符串作为数组下标
当使用1.2.3..n时,直接使用array[2]访问元素;需要遍历数组时,使用以下形式:
str="Allen Jerry Mike Tracy Jordan Kobe Garnet"
split(str,array)
for(i=1;i<=length(array);i++)
print array[i]
当使用字符串作为数组下标时,需要使用array[str]形式访问元素;遍历数组时,使用以下形式:
array["var1"]="Jin"
array["var2"]="Hao"
array["var3"]="Fang"
for(a in array)
print array[a]
数组是以数字为下标的情况,默认是从1开始的
[root@ansible test]# awk 'BEGIN{arr="xiaoli xiaoming fang";split(arr,array1);for(i=1;i<=length(array1);i++) print array1[i]}'
xiaoli
xiaoming
fang
[root@ansible test]#
数组下标以字符串为标示的情况下使用
[root@ansible test]# awk 'BEGIN{array1["num1"]="xiaoli";array1["num2"]="fang";for(arr in array1) print array1[arr]}'
xiaoli
fang
[root@ansible test]#
练习题:
1、统计主机上所有的TCP连接状态数,按照每个TCP状态分类
netstat -an | grep tcp | awk '{array[$6]++}END{for(a in array) print a,array[a]}'
2、计算横向数据总和,计算纵向数据总和
allen 80 90 87 91 348
mike 78 86 93 96 256
Kobe 66 92 82 78 232
Jerry 98 74 66 54 356
Wang 87 21 100 43 322
234 342 451 456 342
- 确保系统中有httpd
Rpm –ql httpd
[root@ansible test]# netstat -an | grep tcp #查看tcp的监听情况
[root@ansible test]# netstat -an | grep tcp | awk '{print $6}'#查看tcp监听端口的第六个元素
Awk统计命令如下
[root@ansible test]# netstat -an | grep tcp | awk 'BEGIN{}{array1[$6]++}END{for( arr in array1) print arr,array1[arr]}'
LISTEN 13
ESTABLISHED 1
[root@ansible test]#
- 计算横向数据总和,计算纵向数据总和