《Linux实战技能100讲》——文本操作

正则表达式与文本搜索

  • 元字符
  • 扩展元字符
  • 文件的查找命令 find
  • 文本内容的过滤(查找) grep

正则表达式的匹配方式

  • 字符串 Do one thing at a time, and do well.
  • 匹配字符 an

元字符

  • . 匹配除换行符外的任意单个字符
  • * 匹配任意一个跟在它前面的字符
  • [ ] 匹配方括号中的字符类中的任意一个
  • ^ 匹配开头
  • $ 匹配结尾
  • \ 转义后面的特殊字符

注:通配符中*表示零个、单个或多个字符,?表示任意单个字符;在元字符中.*相当于通配符中的*。

grep password /root/anaconda-ks.cfg # 匹配到的整行输出
grep pass.... /root/anaconda-ks.cfg
grep pass....$ /root/anaconda-ks.cfg  
grep pass.* /root/anaconda-ks.cfg
grep pass.*$ /root/anaconda-ks.cfg 
grep "\." /root/anaconda-ks.cfg  # 避免.被shell解析

扩展元字符

  • + 匹配前面的正则表达式至少出现一次
  • ? 匹配前面的正则表达式出现零次或一次
  • | 匹配它前面或后面的正则表达式

文件查找find命令

  • 文件名查找命令 find
    • find 路径 查找条件 [补充条件]
cd /etc
find password # 查找内容 passwod
find /etc -name password
# 查找内容
/etc/pam.d/passwd
/etc/passwd
# 查找内容
find /etc -name pass*
man find
find /etc -regex .*wd
find /etc -type f -regex .*wd # 文件类型且符合正则.*wd
find /etc/ -atime 8 # 按时间查找(atime 访问时间)
# atime mtime ctime 

# 通过find找到大部分文件并进行处理
touch /tmp/{1..9}.txt
ls /tmp/*.txt
cd /tmp
find *txt # 同ls /tmp/*.txt查找结果类似
find *txt -exec rm -v { } \; # -v是显示删除进度,{ } \; 指定删除文件
grep pass /root/anconda-ks.cfg | cut -d " " -f 1 # 对grep找到的内容进行剪切以空格为分割并找到第一个字段 # 查找的内容 auth 
cut -d ":" -f7 /etc/passwd # 统计shell
cut -d ":" -f7 /etc/passwd | sort | uniq -c # 统计shell并汇总
cut -d ":" -f7 /etc/passwd | sort | uniq -c | sort -r # 并排序

sed和awk介绍

行编辑器介绍
  • Vim和sed、AWK的区别
  • sed的基本用法演示
  • AWK的基本用法演示
Vim和Sed、AWK的区别
  • 交互式与非交互式
  • 文件操作模式与行操作模式
sed基本用法
  • sed 一般用于对文本内容做替换
    • sed ‘/user1/s/user1/u1/’ /etc/passwd
AWK基本用法
  • AWK一般用于对文本内容进行统计、按需要的格式进行输出
    • cut 命令 :cut -d : -f 1 /etc/passwd
    • AWK命令: awk -F: ‘/wd$/{print $1}’ /etc/passwd

sed替换命令讲解

  • sed的模式空间
  • 替换命令s
sed的模式空间
  • sed的基本工作方式是:
    • 将文件以行为单位读取到内存(模式空间)
    • 使用sed的每个脚本对该行进行操作
    • 处理完成后输出该行
替换命令

注:old字符可使用元字符。

  • sed的替换命令s:
    • sed ‘s/old/new/’ filename
    • sed -e ‘s/old/new/’ -e ‘s/old/new/’ filename … # -e 接多个指令
    • sed -i ‘s/old/new’ ‘s/old/new’ filename … # -i 替换并写回
echo a a a > afile # 新建测试文件
sed 's/a/aa/' afile # aa a a (sed只替换了一次)
sed 's!/!abc!' afile # 由于要替换/,因此需要更换分隔符
sed -e 's/a/aa/' -e 's/aa/bb/' afile  # bb a a
sed 's/a/aa/;s/aa/bb/' afile # 上述的简写方式
sed -i 's/a/aa/;s/aa/bb/' afile # 写入原文件
cat afile # bb a a
sed 's/a/aa/;s/aa/bb/' afile > bfile # 新建另一文件

# 删除
head -5 /etc/passwd
head -5 /etc/passwd | sed 's/...//' # 相当于删除每行的前三个字符
head -5 /etc/passwd | sed 's/s*bin//'
grep root /etc/passwd | sed 's/^root//' # 删除以root开头的root
  • 带正则表达式的替换命令s:
    • sed ‘s/正则表达式/new’ filename
    • sed -r ‘s/扩展正则表达式/new’ filename
# 新建bfile文件
b
a
aa
aaa
ab
abb
abbb
# 新建bfile文件

sed 's/ab*/!/' bfile # 前面一个字符出现零次或多次
#
b
!
!a
!aa
!
!
!
#

sed -r 's/ab+/!/' bfile # 前面一个字符出现一次或多次
#
b
a
aa
aaa
!
!
!
#

sed -r 's/ab?/!/' bfile # 前面出现零次或一次
#
b
!
!a
!aa
!
!b
!bb
#
sed -r 's/a|b/!/' bfile # | 或者
#
!
!
!a
!aa
!b
!bb
!bbb
#

sed -r 's/(aa)|(bb)/!/' bfile # 使用|时多个字符需要使用()
#
b
a
!
!a
ab
a!
a!b
#
# 测试()的回调功能
vim cfile
# 文本内容
axyzb
# 文本内容
sed -r 's/(a.*b)/\1:\1/' cfile #\1表示分组的第一个元素
axyzb:axyzb # 获取内容

sed指令加强版

  • 全局替换
  • 标志位
  • 寻址
  • 分组
  • sed脚本文件
全局替换
  • s/old/new/g
    • g 为全局替换,用于替换所有出现的次数
    • / 如果和正则匹配的内容冲突可以使用其他符号,如:
      • s@old@new@g
head -5 /etc/passwd
head -5 /etc/passwd | etc 's/root/!!!!/' # 默认替换第一个
head -5 /etc/passwd | etc 's/root/!!!!/g' # 全局替换
head -5 /etc/passwd | etc 's/root/!!!!/2' # 只匹配第2次
head -5 /etc/passwd | etc 's/root/!!!!/n' # 只匹配第n次
标志位
  • s/old/new/ 标志位
    • 数字,第几次出现才进行替换
    • g,每次出现都进行替换
    • p 打印模式空间的内容
      • sed -n ‘script’ filename 阻止默认输出
    • w file 将模式空间的内容写入到文件
head -5 /etc/passwd | sed 's/root/!!!!/p' # 处理后的输出,不处理的原本输出
head -5 /etc/passwd | sed -n 's/root/!!!!/p' # 只输出替换后的内容
head -5 /etc/passwd | sed -n 's/root/!!!!/w tmp/a.txt'
标志位
  • 默认对每行进行操作,增加寻址后对匹配的行进行操作
    • /正则表达式/s/old/new/g
    • 行号s/old/new/g
      • 行号可以是具体的行,也可以是最后一行$符号
    • 可以使用两个寻址符号,也可以混合使用行号和正则地址

注:正则表达式和行号是可以混合使用的。

head -6 /etc/passwd | sed '1s/adm/!/' # 第一行替换
head -6 /etc/passwd | sed '1,3s/adm/!/' # 第一行到第三行替换
head -6 /etc/passwd | sed '1,$s/adm/!/' # 第一行到最后一行替换
head -6 /etc/passwd | sed '/root/s/adm/!/' # root行的bash进行替换
head -6 /etc/passwd | sed '/^bin/,$s/nologin/!/'
分组
  • 寻址可以匹配多条命令
  • /regular/{s/old/new/;s/old/new/}
脚本文件
  • 可以将选项保存为文件,使用-f加载脚本文件
  • sed -f sedscript filename

sed其他指令

  • 删除命令
  • 追加、插入、更改
  • 打印
  • 下一行
  • 读文件和写文件
  • 退出命令
删除命令
  • [寻址]d
    • 删除模式空间内容,改变脚本的控制流,读取新的输入行(d匹配后整行都会被删除)
cat bfile
#
b
a
aa
aaa
ab
abb
abbb
#

sed '/ab/d' bfile
#
b
a
aa
aaa
#

sed '/ab/d;s/a/!/' bfile # 删除之后的内容不会被改变(改变控制流)
#
b
!
!a
!aa
#

sed '/ab/d;=' bfile # =为打印行号
#
1
b
2
a
3
aa
4
aaa
#
追加插入和更改
  • 追加命令 a
  • 插入命令 i
  • 更改命令 c
cat bfile
#
b
a
aa
aaa
ab
abb
abbb
#

sed 'ab/i hello' bfile # 只要匹配到ab就会插入hello,上一行插入
#
b
a
aa
aaa
hello
ab
hello
abb
hello
abbb
#

sed 'ab/a hello' bfile # 只要匹配到ab就会插入hello,下一行插入
#
b
a
aa
aaa
ab
hello
abb
hello
abbb
hello
#

sed 'ab/c hello' bfile # 只要匹配到ab就会改写成hello
#
b
a
aa
aaa
hello
hello
hello
#

sed 'ab/r afile' bfile # 当遇到bfile中的ab时添加afile里面的内容
#
b
a
aa
aaa
ab
bb a a
abb
bb a a
abbb
bb a a
#
读文件和写文件
  • 读文件命令r
  • 写文件命令w
下一行
  • 下一行命令 n
  • 打印行号命令 =
打印
  • 打印命令 p
sed '/ab/p' bfile # 把匹配的行进行输出(匹配到的行再输出一次)
#
b
a
aa
aaa
ab
ab
abb
abb
abbb
abbb
#

sed -n '/ab/p' bfile # 只输出匹配的行
退出命令
  • 提出命令 q
  • 哪个效率会更高呢?
    • sed 10q filename
    • sed -n 1,10p filename

注:q的指令性能高于p,q只读取对应的行数到内存中。

seq 1 10 # 产生1至10的数字
1
2
3
4
5
6
7
8
9
10

seq 1 1000000 > lines.txt
wc -l lines.txt # 1000000 lines.txt
sed -n 1,10p lines.txt
time sed -n '1,10p' lines.txt  # 0.118s
time sed -n '10q' lines.txt  # 0.003s

sed多行模式空间

  • 为什么要有多行模式
  • 多行模式处理命令N、D、P
为什么要有多行模式
  • 配置文件一般为单行出现
  • 也有使用XML或JSON格式的配置文件,为多行出现
多行匹配命令
  • N 将下一行加入到模式空间
  • D 删除模式空间中的第一个字符到第一个换行符
  • P 打印模式空间中的第一个字符到第一个换行符
vim a.txt
# 文本内容
hel
lo
# 文本内容
sed 'N;s/hel\nlo/!!!/' a.txt # !!!
sed 'N;s/hel.lo/!!!/' a.txt # !!! 使用.来匹配换行符
cat > b.txt << EOF # 输入重定向
> hell
> o bash hel
> lo bash
> EOF
cat b.txt
#
hell
o bash hel
lo bash
#
sed 'N;s/\n//;s/hello bash.hello sed\n/;P;D' b.txt # 将换行符删除
# 
hello sed
 hello sed
#
sed 'N;N;s/\n//;s/hello bash.hello sed\n/;P;D' b.txt # 每三行进行处理

sed保持空间

  • 什么是保持空间
  • 保持空间命令
什么是保持空间
  • 保持空间也是多行的一种操作方式
  • 将内容暂存在保持空间,便于做多行处理

在这里插入图片描述
注:在模式空间的同时再开辟一段内存空间。

保持空间命令
  • h和H将模式空间内容存放到保持空间
  • g和G将保持空间内容取出到模式空间
  • x交换模式空间和保持空间内容

小写的h、g是覆盖模式,大写的H、G是追加模式。
可应用在行之间顺序的互换。

实现行数翻转(这块难以理解)

head -6 /etc/passwd | cat -n #
head -6 /etc/passwd | cat -n | tac # 逆序输出
cat -n /etc/passwd | head -6 | sed -n '1h;1!G;$!x;$p' # 翻转第一行到第六行,其中很多细节目前自己无法掌握
cat -n /etc/passwd | head -6 | sed -n 'G;h' # 上述一样的功能实现
cat -n /etc/passwd | head -6 | sed -n 'G;h;$p' 
cat -n /etc/passwd | head -6 | sed -n '1!G;h;$p' 
cat -n /etc/passwd | head -6 | sed '1!G;h;$!d' 

认识awk

功能:进行格式调整和相应输出。

  • AWK和sed的区别
  • AWK脚本的流程控制
AWK和sed的区别
  • AWK更像是脚本语言
  • AWK用于"比较规范"的文本处理,用于统计数量并输出指定字段
  • 使用sed将不规范的文本,处理为"比较规范"的文本
AWK脚本的流程控制
  • 输入数据前例程 BEGIN{ }
  • 主输入循环{ }
  • 所有文件读取完成例程 END{ }

注:上述流程并非都需要完整写完,一般可直接书写主输入循环。

awk的字段

  • 每行称作AWK的记录
  • 使用空格、制表符分隔开的单词称作字段
  • 可以自己指定分隔的字段
字段的引用
  • awk中使用$1、$2…$n表示每一个字符
    • awk ‘{ print $1,$2,$3}’ filename
  • awk可以使用-F选项改变字段分隔符
    • awk -F ‘,’ ‘{ print $1,$2,$3}’ filename
    • 分隔符可以使用正则表达式
awk -F "'" '/^menu/{ print $2 }' /boot/grub2/grub.cfg # 测试取出指定的内核
awk -F "'" '/^menu/{ print x++,$2 }' /boot/grub2/grub.cfg # 显示行号,默认变量为0

awk表达式

  • 赋值操作符
  • 算数操作符
  • 系统变量
  • 关系操作符
  • 布尔操作符
赋值操作符
  • =是最常用的赋值操作符
    • var1 = “name”
    • var2 = “hello” “world”
    • var3 = $1
  • 其他赋值操作符
    • ++ – += -= *= /= %= ^=
算数操作符
  • 算数操作符
    • + - * / % ^
系统变量

awk自定义的系统变量。

  • FS和OFS字段分隔符,OFS表示输出的字段分隔符
  • RS记录分隔符(RS默认是换行符)
  • NR和FNR行数
  • NF字段数量,最后一个字段内容可以用$NF取出
head -5 /etc/passwd | awk -F ":" '{print $1}' # 取得第一个变量
head -5 /etc/passwd | awk 'BEGIN{FS=":"}' '{print $1}' # 注意begin在读取之间进行设置的
head -5 /etc/passwd | awk 'BEGIN{FS=":"}' '{print $1,$2}' 
head -5 /etc/passwd | awk 'BEGIN{FS=":";OFS="-"}' '{print $1,$2}' # 输入和输出的格式不同
head -5 /etc/passwd | awk '{print NR,$0}' # 输出行号
awk '{print FNR,$0}' /etc/hosts /etc/hosts # 输出多个文件的行号
head -5 /etc/passwd | awk 'BEGIN{FS=":"}{print NF}' # 每行字段的个数
head -5 /etc/passwd | awk 'BEGIN{FS=":"}{print $NF}' # 输出每行字段的内容
关系操作符
  • 关系操作符
    • <、 > 、<=、 >=、 ==、 !=、 ~、 !~ (~运用在字符匹配上)
布尔操作符
  • 关系操作符
    • && || !

awk判断和循环

  • 条件语句
  • 循环
条件语句
  • 条件语句使用if开头,根据表达式的结果来判断执行哪条语句
if(表达式)
	awk语句1
[else
	awk语句2
]
  • 如果有多个语句需要执行可以使用{ }将多个语句括起来
cat kpi.txt
# 文本内容
user1 70 72 74 76 74 72
user2 80 82 84 82 80 78
user3 60 61 62 63 64 65
user4 90 89 88 87 86 85
user5 45 60 63 62 61 50
# 文本内容
#目标: 第二列字段大于等于80进行输出
awk '{if($2>=80) print $1}' kpi.txt
#
user2
user4
#

awk '{if($2>=80) {print $1;print $2;} }' kpi.txt
循环
  • while循环
while(表达式)
	awk语句1
  • do循环
do{
	awk语句1
}while(表达式)
  • for循环
for(初始值;循环判断条件;累加)
	awk语句1
  • 影响控制的其他语句
    • break
    • continue
cat kpi.txt
# 求总成绩和平均成绩
awk '{sum=0; for(c=2;c<NF;c++) sum+=$c;print sum/(NF-1)}' kpi.txt # sum此处初始化的原因在于当处理第二个用户时不使用上一个sum的值

awk数组

  • 数组的定义
  • 数组的遍历
  • 删除数组
  • 命令行参数数组
数组的定义
  • 数组:一组有某种关联的数据(变量),通过下标依次访问
    • 数组名[下标] = 值
    • 下标可以使用数字也可以使用字符串
数组的遍历
for(变量 in 数组名)
	使用 数组名[变量]的方式依次对每个数组的元素进行操作
删除数组
  • 删除数组
    • delete 数组[下标] # 删除某个下标
cat kpi.txt
awk '{ sum=0; for(column=2;column<=NF;column++) sum+=$column; average[$1]=sum/(NF-1)} END{ for(user in average) print user,average[user]}' kpi.txt 每个用户的平均值
#
user1 73
user2 81
user3 62.5
user4 87.5
user5 56.8333
#

awk '{ sum=0; for(column=2;column<=NF;column++) sum+=$column; average[$1]=sum/(NF-1)} END{ for(user in average) sum2+=average[user];print sum2}' kpi.txt # 平均值之和
使用脚本方式
vim avg.awk # 将awk编辑成脚本
# 将上述命令放入脚本文件中
awk -f avg.awk kpi.txt # 使用-f来运行脚本
命令行参数数组
  • 命令行参数数组
    • ARGC
    • ARGV

作用:多行之间进行交互。

vim arg.awk
# 文本内容
BEGIN{
	for(x=0;x<ARGC;x++)
		print ARGV[x]
	print ARGC
}
# 文本内容
awk -f arg.awk 11 22 33
#
awk # 命令名称
11
22
33
4
#

awk数组功能的使用

vim result.awk
# 文本内容
{
sum = 0
for(column = 2; column <= NF;column++)
	sum += $column
average[$1] = sum  / (NF-1)

# 字符等级
if(average[$1] >= 80)
	letteer = "S"
else if(average[$1] >= 70)
	letter = "A"
else if(average[$1] >= 60)
	letter = "B"
else
	letter = "C"
	
print $1,average[$1],leter

letter_all[letter]++  # 所有的字符等级(关联数组方式来计数)

}
END{
for(user in average)
	sum_all += average[user]

avg_all = sum_all / NR

for(user in average)
	if(average[user] > avg_all)
		above++
	else
		below++
print "above",above
print "below",below
print "S:",letter_all["S"]
print "A:",letter_all["A"]
print "B:",letter_all["B"]
print "C:",letter_all["C"]
}
# 文本内容
awk -f result.awk kpi.txt
#
user1 73 A
user2 81 S
user3 62.5 B
user4 87.5 S
user5 56.8333 C
average all:72.1667
above 3
below 2
s: 2
A: 1
B: 1
C: 1
#
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值