关于linux三剑客
- grep,过滤关键字信息数据。主要是用于查文本内的数据
- sed ,对文本数据进行编辑,修改原文件内容
- awk,对文件数据过滤,提取,并且能实现,格式化输出
- awk对文件数据处理后,还能更美观的展示数据
再谈三剑客
- grep,擅长单纯的查找或匹配文本内容
- sed,更适合编辑、处理匹配到的文本内容
- awk,更适合格式化文本内容,对文本进行复杂处理后、更友好的显示
三个命令称之为Linux的三剑客
sed
了解sed
sed是什么
- sed是一个软件
- sed提供的加工的命令
- 给sed提供的源数据可以是键盘输入,文件,也可以是管道stdin。
sed功能
sed命令是操作,过滤和转换文本内容的强大工具,全部以行为单位操作文本内容
常用功能有
- 对文本内容增删改查,其中查询功能最常用
- 过滤指定字符串
- 去除指定行
sed语法
sed [选项] [sed内置命令字符] [输入文件]
说明:
1.注意 sed 软件及后面选项,sed 命令和输入文件,每个元素之间都至少有一个空格
2.为了避免混淆,文本称呼sed为sed软件.sed-commands(sed命令)是sed软件内置的一些命令选项,为了和前面的 options(选项)区分,故称为sed命令.
3.sed-commands 既可以是单个sed 命令,也可以是多个sed命令组合.
4.input-file(输入文件)是可选项,sed 还能够从标准输入或管道获取输入
5.sed还可以和正则结合使用
#语法举例
sed 's#替换前的数据#替换后的数据#' file.txt
# 将t1.log中的hello替换为Hello
sed 's/hello/Hello/' t1.log
sed命令执行图解
sed参数
sed默认修改的是模式空间内的数据
(人话:sed读取了一行文本数据,放入到内存里进行修改,修改的结果默认不会写入到文件中,只是在内存里修改,且打印让你看到修改的结果)
把修改的结果写入到文件,就得借助参数的功能,记得加-i!!!!
-i #in place ,把sed处理的结果,写入到文件,且不在终端打印了
sed -i 's/替换前的数据/替换后的数据/' file.txt
options[选项]
解释说明
-n #silent,取消默认的 sed 软件的输出,常与 sed 命令的 p 连用
-e #expression,一行命令语句可以执行多条 sed 命令
-f #file,选项后面可以接 sed 脚本的文件名
-r #regular,使用正则拓展表达式,默认情况 sed 只识别基本正则表达式
-i #in place,直接修改文件内容,而不是输出终端,如果不使用-i 选项 sed 软件只是修改在 内存中的数据,并不影响磁盘上的文件
p #打印修改后结果,一般和-n一起用
#替换后仅输出被修改内容,不输出全文
sed 's/yuchao/Dahong/p' -n chaoge.txt
I am Dahong.
sed命令
sed软件
sed提供了很多功能的指令
在某一行插入数据
替换字符数据
sed-commands[sed 命令]
解释说明
a 追加,在指定行后添加一行或多行文本
c 取代指定的行
d 删除指定的行
D 删除模式空间的部分内容,直到遇到换行符\n 结束操作,与多行模式相关
i 插入,在指定的行前添加一行或多行文本
h 把模式空间的内容复制到保持空间
H 把模式空间的内容追加到保持空间
g 把保持空间的内容复制到模式空间
G 把保持空间的内容追加到模式空间
x 交换模式空间和保持空间的内容
l 打印不可见的字符
n 清空模式空间,并读取下一行数据并追加到模式空间
N 不清空模式空间,并读取下一行数据并追加到模式空间
p 打印模式空间的内容,通常 p 会与选项-n 一起使用
P(大写) 打印模式空间的内容,直到遇到换行符\你结束操作
q 退出 sed
r 从指定文件读取数据
s 取代,s#old#new#g==>这里 g 是 s 命令的替代标志,注意和 g 命令区分
w 另存,把模式空间的内容保存到文件中
y 根据对应位置转换字符
:label 定义一个标签
t 如果前面的命令执行成功,那么就跳转到 t 指定的标签处,继续往下执行后 续命令,否则,仍然继续正常的执行流程
sed匹配文件行范围
sed默认是一行一行,处理文件中每一行的数据
文件有100行
sed匹配文本范围
范围 | 解释 |
---|---|
空地址 | 全文处理 |
单地址 | 指定文件某一行 |
/pattern/ | 被模式匹配到的每一行 #写入正则,字符数据# |
范围区间 | 10,20 十到二十行 ,10,+5第10行向下5行 ,/pattern1/,/pattern2/ |
步长 | 1~2,表示1、3、5、7、9行 ,2~2两个步长,表示2、4、6、8、10、偶数行 |
sed处理文件行范围语法
sed命令语法 | 作用 |
---|---|
3 | 操作第三行 |
3,6 | 操作3~6行,包括3和6行 |
3,+5 | 操作3到3+5(8)行,包括3,8行 |
1~2 | 步长为2,操作1,3,5,7..行 |
3,$ | 对3到末尾行操作,包括3行 |
/yuchao/ | 对匹配字符yuchao的该行操作 |
/yuchao/,/chaoge/ | 对匹配字符yuchao到chaoge的行操作 |
/yuchao/,$ | 对匹配字符yuchao到结尾的行操作 |
/yuchao/,+2 | '/yuchao/,+2p',打印匹配到yuchao的行,包括其后2行 |
#删除第三行数据
sed '3 d' t1.log
#删除文件的3到6行
sed '3,6 d' t1.log
#删除第三行开始,向下2行
sed '3,+2 d' t1.log
#删除奇数行 1,3,5,7,9
sed '1~2 d' t1.log
#删除偶数行 2,4,6,8
sed '2~2 d' t1.log
#删除第四行到结尾
sed -e '4,$ d' t1.log
加油
奥力给
My name is yuchao.
#找到game那一行,且删掉
sed '/game/ d' t1.log
加油
奥力给
My name is yuchao.
I teach linux.
My qq is 877348180.
My website is http://www.yuchaoit.cn
#删除从game这一行到结尾
sed '/game/,$ d' t1.log
加油
奥力给
My name is yuchao.
I teach linux.
#删除文件中所有包含game的行,以及它下一行
sed '/game/,+1 d' t1.log
加油
奥力给
My name is yuchao.
I teach linux.
My website is http://www.yuchaoit.cn
打印行范围练习
sed提供打印的命令是p
#打印game那一行,以及game的后1行
sed '/game/,+1 p' t1.log -n # -n取消默认输出
we all like games
奥力给
I like play computer game.
My qq is 877348180.
测试数据
My name is yuchao.
I teach linux.
I like play computer game.
My qq is 877348180.
My website is http://www.yuchaoit.cn
Sed 默认不修改源文件
sed默认的命令操作,不会修改源文件,你看到的终端结果,只是sed把模式空间的内容打印给你看了而已。
得用sed -i 参数修改源数据。
sed工作图解
###-n选项
修改字符与取消默认输出
-e选项
-e选项用于接上sed多个命令,可以达到和 ;分号同样的效果
#语法
sed -e 'sed命令' -e 'sed命令' -e 'sed命令'
#提取1,2,4行信息
sed -e '1p' -e '2p' -e '4p' t1.log -n
#sed提取ip地址
ifconfig ens33 | sed -e '2s/^.*inet//' -e '2s/netmask.*//p' -n
192.168.0.242
; 分号
分号也用于执行多条命令,和linux基础命令一样支持这种写法。可以达到和-e同样的效果。
单独提取出1,2,4行信息
#提取1,2,4行信息
sed '1p;2p;4p' t1.log -n
感叹号取反
感叹号在很多命令里都是取反的作用,sed也一样,但是是和sed命令
结合用,如!d
#除了有yuchao字符的行,其他行都删除
sed '/yuchao/ !d' test.log
#删掉除了My开头的行
sed '/^My/!d' test.log
sed忽略大小写的指令
# sed提供了I指令,用于忽略大小写
#删除My开头的行
sed '/^My.*/ Id' test.log
w命令
作用是将sed操作结果,写入到指定文件中
#语法
sed '/模式/w new_file' old_file
#找出computer这一行,数据写入到game2.log文件中
sed -n '/computer/w game2.log' t1.log
cat game2.log
I like play computer game.
#替换文件中所有的yuchao为老于,新数据写入 yu.log
sed -n 's#yuchao#老于#gw yu.log' t1.log
cat yu.log
me is 老于. you can call me 老于.
My website is http://www.老于it.cn , and another website is https://www.老于.top/
sed增加命令
"a":追加文本到指定行,记忆方法:a 的全拼是 apend,,意思是追加
3a 表示在第三行下面追加数据
"i":插入文本到指定行前,记忆方法:i 的全拼是 insert,意思是插入
3i 在第三行上面插入数据
sed单行增加命令
语法
sed '行号 sed指令 你想添加的字符数据' 源文件
sed增加数据的命令
a 追加,在指定行后添加一行或多行文本
i 插入,在指定的行前添加一行或多行文本
实践
在文件第二行后,插入数据,"今天又是美好的一天"
sed '2 a "今天又是美好的一天" ' t1.log
sed '2 a "今天又是美好的一天" ' t1.log
My name is yuchao.
I teach linux.
"今天又是美好的一天"
I like play computer game.
My qq is 877348180.
My website is http://www.yuchaoit.cn
在第二行前,插入数据
sed '2 i 今天雾霾比较大' t1.log
cat实现多行文本追加
cat >>my.log<<EOF
你好
我好
他也好
EOF
echo 追加多行数据
1.多次追加
echo "你好" >> tt.log
2.使用换行符,一次添加多行数据
echo -e 'hello\nworld\n你好\n我也好' > hello.log # -e 参数为了识别\n换行符!!!
hello
world
你好
我也好
用法如下
[242-yuchao-class01 root ~]#echo -e "hello\nworld\n你好\n我也好" > hello.log
[242-yuchao-class01 root ~]#cat hello.log
hello
world
你好
我也好
####sed多行增加命令(\n)
无论是cat、还是echo,都只能往文件末尾追加内容。
而sed是按行处理文本,可以指定要处理的行,也就是在指定行插入字符数据。
使用\n添加多行数据
给t1.log 开头,添加两行数据
加油
奥力给
sed -i '1i 加油\n奥力给' t1.log
cat -n t1.log
1 加油
2 奥力给
3 My name is yuchao.
4 I teach linux.
5 I like play computer game.
6 My qq is 877348180.
7 My website is http://www.yuchaoit.cn
sed和vim的一些指令有共性
vim
插入模式
a
i
o
sed
数据插入命令
a 在指定的行下面插入
i 在指定行上面插入数据
sed删除命令
我们以前是用vim编辑文本,也是通过d命令,剪切(删除)数据。
sed关于删除的命令
#删除指定行
sed 'nd' <文件名>
#删除多行数据,删除m到n行
sed 'm,nd' <文件名>
#删除全部数据
sed 'd' <文件名>
#删除不相邻的多行(这里用删除1,3,4行举例)
sed '1d;3d;4d' <文件名>
#sed可以和正则结合使用
sed '/正则/ d' <文件名>
sed默认是多行处理所有文本,如果不指定范围,sed默认是删除所有文本行数据了
测试数据:
My name is yuchao. you can call me yuchao.
I teach linux.
I like play computer game.
My qq is 877348180.
My website is http://www.yuchaoit.cn , and another website is https://www.yuchao.top/
示例:
#删除第二行数据
sed '2 d' t1.log
加油
My name is yuchao.
I teach linux.
I like play computer game.
My qq is 877348180.
My website is http://www.yuchaoit.cn
#sed删除1到4行
sed '1,4d' t1.log
#删除全部数据
sed 'd' t1.log
#删除1,2,4行
sed '1d;2d;4d' t1.log
#删除有game的行
sed '/game/ d' t1.log
#删除有game和http的行
sed '/game/d; /http/d' test.log
#删除My开头的行
sed I '/^My.*/ d' test.log #sed命令使用 I参数忽略大小写
#删除以.结尾的行
sed '/\.$/d' test.log
#删除从第二行到有qq的那行
sed '2,/qq/ d' test.log
#删除2和5两行
sed '2d;5d' test.log
#删除3行到尾行
sed '3,$d' test.log
#删除偶数行
sed '1~2d' test.log
#删除奇数行
sed '2~2d' test.log
小结
工作里用的最多的还是指定数字行号,或者完整字符精确匹配,不容易出错。
而正则或是其他模糊匹配,很容易改错,了解即可。
sed修改命令
修改数据,是一大重点,因为我们需要用sed来修改各种配置文件,sed这种非交互式修改文件内容,在脚本中实现自动化修改是最常见的。
如修改nginx的端口;
修改mysql的数据存储路径;
替换整行命令(c)
将选定的行整行替换为新文本
# 语法
sed '行号 c 新文本'
#例如,将第二行整行替换为I love linux , python !
sed '2c I love linux , python !' t1.log
替换字符(s命令)
这个功能占用了sed使用率的80%,基本替换的功能都是这个s指令。
# s是将每一行第一处匹配的字符替换,是每行!!不是全文
# 语法有三种
sed 's#替换的字符#字符#' 文件名 #(强烈建议用个)
sed 's/被替换的字符/新字符/' 文件名
sed 's@替换的字符@符@' 文件名
# 建议用这个#号,作为分隔符,因为其他符号也经常用到,例如 / ,否则你就得写转义符
# 例如如下恶心的写法
's\//opt/data/\//opt/new_data/\/g'
# 这个# 称作边界符
#后面加g全局替换,不加替换一次
#替换每行第一处
sed 's/替换前字符/替换后字符/' file
#全局替换,global 全局替换
sed 's/替换前字符/替换后字符/g' file
-i 选项、参数,直接修改文件
sed默认是修改内存中的模式空间数据,不会修改源文件,使用-i会修改源文件,修改磁盘上的文件数据。
测试数据
My name is yuchao. you can call me yuchao.
I teach linux.
I like my play computer game.
My qq is 877348180.
My website is http://www.yuchaoit.cn , and another website is https://www.yuchao.top/
#将yuchao替换为老于,替换一次
sed 's#yuchao#老于#' test.log
#将yuchao替换为老于,全局替换
sed 's#yuchao#老于#g' test.log
#替换第三行的computer改为linux
sed '3s #computer#linux#' test.log
#所有的开头的My改为His
sed 's #^my#His#gI' test.log #注意,sed提供了忽略大小写的命令,大写的 I
报错记录
sed 's #^My#His#gI' test.log
#改命令报错如下
#sed: -e expression #1, char 15: unterminated `s' command
#解决方案:s和#之间不要加空格
sed 's#^my#His#gI' test.log
#写了正则没加-r参数也会报上述错误
echo 'I am teacher yuchao,welcome to my linux lesson!' | sed 's/^.*,(.*)\s+to.*/\1/'
#修改后
echo 'I am teacher yuchao,welcome to my linux lesson!' | sed -r 's/^.*,(.*)\s+to.*/\1/'
welcome
sed使用shell变量
#sed要替换数据,替换的内容是从shell变量里拿到的
new_name="彭于晏"
#注意单引号、双引号的对变量的解析作用!!!!!
sed "s#yuchao#$new_name#g" t1.log
My name is 彭于晏. you can call me 彭于晏.
I teach linux.
I like play computer game.
My qq is 877348180. my num is 1555555555.
My website is http://www.彭于晏it.cn , and another website is https://www.彭于晏.top/
sed使用正则分组替换
sed的扩展正则参数:-r
grep的扩展正则参数:-E
#语法:
sed 's#正则语法#新内容#' 文件名
#sed软件也提供了 \(\)分组功能
#使用\1引用第一个括号的数据
#\2引用第二个括号的数据
#sed最多记住9个分组
#() \1向后引用分组数据
测试数据
echo 'I am teacher yuchao,welcome my linux course' | sed -r '^.*,(.*)\s+m.*'
提取出welcome这个单词
echo 'I am teacher yuchao,welcome my linux course' | sed -r 's/^.*,(.*)m.*/\1/g'
welcome
#别忘记加-r参数!!!!!
分组取出ip
\s 表示单个空格
#去头去尾法
ifconfig ens33 | sed -e '2s/^.*inet//' -e '2s/netmask.*//p' -n
192.168.0.242
#分组提取法
ifconfig eth0 | sed -re '2s/^.*inet\s+(.*)\s+netmask.*/\1/p' -n
172.28.81.42
sed查询
sed的修改,删除最重要的学完了
接下来看看sed的查询,也是比较实用的,比起cat、more要方便的多。
sed打印命令p 打印sed正则处理后的数据
并且sed默认打印模式空间,可以用-n取消
文本,10数据 > sed 一行一行的读取,编辑 >> 打印
固定用法,只要使用到了p打印些数据,就是想输出指定数据
必然用-n取消默认打印,目的是,只看到你想p打印的那些数据
#打印第二行
sed -n '2p' test.log
#打印前三行
sed -n '1,3p' test.log
#只显示qq号那一行
sed -nr '/[0-9]{10}/p' test.log
#找出http和linux的行(3写法)
sed -nr '/linux|http/p' test.log
sed -ne '/linux/p' -e '/http/p' test.log
sed -n '/linux/p;/http/p' test.log
找出http和linux的行
-e 多次编辑
[242-yuchao-class01 root ~]#sed -e '/http/p' -e '/linux/p' t1.log -n
I teach linux.
My website is http://www.yuchaoit.cn , and another website is https://www.yuchao.top/
[242-yuchao-class01 root ~]#sed '/http/p;/linux/p' -n t1.log
I teach linux.
My website is http://www.yuchaoit.cn , and another website is https://www.yuchao.top/
awk
更适合格式化文本内容,对文本进行复杂处理后、更友好的显示
awk用处
以下部分内容需要结合shell编程
- 对文本行数据提取数据字段
- 模式、动作
- 正则模式匹配
- 匹配到数据后的动作
- awk执行流程
- awk内置变量(默认预留变量)
- awk数组
- awk循环、条件判断
- awk内置函数
- awk参数传递
- awk程序开发
学awk就两件事、行、列
对行操作、对列操作
如何分割数据,
如何输出数据,指定第一行,到第三行
awk的语法格式
awk 指令是由模式,动作,或者模式和动作的组合
组成.
- 模式即 pattern,可以类似理解成 sed 的模式匹配,可以由表达式组成,也可以使两个正斜杠之间的正则表 达式.比如 NR==1,这就是模式,可以把他理解为一个条件.
- 动作即 action,是由在大括号里面的一条或多条语句组成,语句之间使用分号隔开,如下 awk 使用格式
- Action指的是动作,awk擅长文本格式化,且输出格式化后的结果,因此最常用的动作就是
print
awk模式、动作
- 模式,是指,要操作哪些行
- 动作,是指,找到这些行之后,干什么,如何处理
生成测试数据
[242-yuchao-class01 root ~]#echo cc{01..50} | xargs -n 5
cc01 cc02 cc03 cc04 cc05
cc06 cc07 cc08 cc09 cc10
cc11 cc12 cc13 cc14 cc15
cc16 cc17 cc18 cc19 cc20
cc21 cc22 cc23 cc24 cc25
cc26 cc27 cc28 cc29 cc30
cc31 cc32 cc33 cc34 cc35
cc36 cc37 cc38 cc39 cc40
cc41 cc42 cc43 cc44 cc45
cc46 cc47 cc48 cc49 cc50
写入文件,生成测试数据文件
echo cc{01..50} | xargs -n 5 > yuchao.log
无模式、只有动作
不写模式、默认处理每一行
#1. 直接输出源文件,所有内容
#动作是 {print $0} 这个$0是表示全部列的数据
#关于字段的取值语法
#$0 表示所有字段数据
#$1 第一列数据
#$2 第二列数据
#依次类推
awk '{print $0}' test_awk.log
cc01 cc02 cc03 cc04 cc05
cc06 cc07 cc08 cc09 cc10
cc11 cc12 cc13 cc14 cc15
cc16 cc17 cc18 cc19 cc20
cc21 cc22 cc23 cc24 cc25
cc26 cc27 cc28 cc29 cc30
cc31 cc32 cc33 cc34 cc35
cc36 cc37 cc38 cc39 cc40
cc41 cc42 cc43 cc44 cc45
cc46 cc47 cc48 cc49 cc50
#2.输出每一行数据,但是只要第一列的数据
awk '{print $1}' test_awk.log
#3. 输出每一行数据,只要第二列的数据
awk '{print $2}' test_awk.log
#4. 输出每一行数据,只要第一列和 第三列的数据
awk '{print $1,$3 }' test_awk.log
cc01 cc03
cc06 cc08
cc11 cc13
cc16 cc18
cc21 cc23
cc26 cc28
cc31 cc33
cc36 cc38
cc41 cc43
cc46 cc48
行变量NR、匹配范围语法
- 刚才是没指定处理那一行,默认是所有行
- 可以指定对某一行处理了
#语法说明,内置变量NR,表示awk处理的每一行
#number of record (记录,行的意思)
#NR代表行号
#格式说明
#NR 行
#直接打印这个内置变量,表示取当前行的号码
#在开头显示行号
awk '{print NR,$0}' test_awk.log
#在结尾显示行号
awk '{print $0,NR}' test_awk.log
# NR==行号
#打印第二行的所有字段数据
awk 'NR==2{print $0}' test_awk.log
#打印第二行的,第1列,和第四列数据
awk 'NR==2{print $1,$4}' test_awk.log
cc06 cc09
# NR>=行号
# NR<=行号
# NR>=N && NR<=M 从N行到M行
# NR>N || NR<M 行号大于N或小于M的行
列变量NF、每一列的字段
#number of field (字段的数量)
#NF 列数
#直接写NF变量表示每一行字段的总数(列数)
#查看每一行有多少个字段
awk '{print $0,NF}' test_awk.log
#输出列:
#位置变量说明
#直接写NF变量表示每一行字段的总数
#查看每一行有多少个字段
#这个NF,默认表示,字段的总数
awk '{print $0,NF}' test_awk.log
$1,$2,$3
, 输出分隔符,默认逗号,awk输出每一列的分隔符是,空格
$0 输出所有字段
$1 输出第一列
$2 输出第二列的数据
$3 输出第三类的数据
... 依次类推
$NF #输出最后一列 注意区分 $NF 和 NF !!!!
awk '{print $NF}' test_awk.log
$(NF-1) #输出倒数第2列
最后一列图解
只有模式,不写动作(懒人写法,别用)
awk不指定动作的话,默认打印整行信息
#提取前五行的数据,请务必加上动作,且显示行号在前面
awk 'NR<=5{print NR,$0}' test_awk.log
只有动作、不写模式
没有模式,也就是没限定条件,
Awk默认处理所有行
打印前三列的数据
awk '{print $1,$2,$3}' test_awk.log
多个模式和动作(解释NR、NF)
指定行,
NR==4
,number of record,行号的记录指定动作,
bashawk '{print $0,NF,NR}' test_awk.log cc01 cc02 cc03 cc04 cc05 5 1 cc06 cc07 cc08 cc09 cc10 5 2 cc11 cc12 cc13 cc14 cc15 5 3 cc16 cc17 cc18 cc19 cc20 5 4 cc21 cc22 cc23 cc24 cc25 5 5 cc26 cc27 cc28 cc29 cc30 5 6 cc31 cc32 cc33 cc34 cc35 5 7 cc36 cc37 cc38 cc39 cc40 5 8 cc41 cc42 cc43 cc44 cc45 5 9 cc46 cc47 cc48 cc49 cc50 5 10
- 内置变量$0表示整行数据
- NF表示Number of filed,字段的数量,表示这一行数据分了几列
- NF表示字段总数
- $NF表示取最后一个字段的值
- NR表示,number of record,行号的记录,表示在处理第几行
#打印前四行数据,要求输出每一行的行号、字段数、以及对应行的数据
awk 'NR<=4{print NR,NF,$0 }' test_awk.log
1 5 cc01 cc02 cc03 cc04 cc05
2 5 cc06 cc07 cc08 cc09 cc10
3 5 cc11 cc12 cc13 cc14 cc15
4 5 cc16 cc17 cc18 cc19 cc20
对、行、列数据的快速入门操作
awk快速入门小结
pattern和action都要用单引号,防止shell作特殊解释(是交给awk去执行的,而不是bash)
不指定模式,awk默认处理输入的文件数据,每一行,每一列
- 如果指定模式,例如指定的行,awk就处理指定那一行的数据
awk的动作,必须写在花括号里
bash{print}
,括号里写入awk提供的命令。
- 如果没有
{ }
花括号,就会被识别为patter,而不是action
- 如果没有
注意给awk传入数据,一般都是file
也可以是管道传递的数据
#拿到第二行的,倒数第二列的数据
cat test_awk.log | awk 'NR==2{print $(NF-1)}'
cc09
图解awk执行过程
awk其他内置变量
参考国外awk网址
NR=======行号
NF=======字段数量
FS===========数据输入的字段分隔符,列分隔符默认是【空格】
RS============record separator 行分隔符,行分隔符默认是【换行符】
图解FS变量,,,,,,,,,,,,关于列的分隔符
图解RS变量,,,,,,,,,,,,,,,,关于行分隔符
awk的其他内置变量如下。
#FILENAME:当前文件名
===================awk在数据输入时,的一个分隔符===================
#FS:字段分隔符,默认是空格和制表符。
Input field separator variable.输入字段分隔符变量。
#RS:行分隔符,用于分割每一行,默认是换行符。
Record Separator variable,行分隔符变量
============awk处理完毕后,打印的数据格式,分隔符=================
#OFS:输出字段的分隔符,用于打印时分隔字段,默认为空格。
#Output Field Separator Variable,输出字段分隔符变量
#ORS:输出记录的分隔符,用于打印时分隔记录,默认为换行符。
#Output Record Separator Variable,输出记录分隔符变量
#OFMT:数字输出的格式,默认为%.6g。
RS变量/ORS变量
RS变量作用是, 行分隔符========awk在数据输入时,读取的一个行分隔符
ORS ,output RS =======awk在{print $0} 打印数据后,的一个行分隔符==
图解awk执行的输入、输出
awk 对每个要处理的输入数据认为都是具有格式和结构的,而不仅仅是一堆字符串
默认情况下,每一行 内容都是一条记录,并以换行符分隔**(\n)**结束
- awk默认下,每一行就是每一个record(记录)
- RS 即 record separator 输入输入数据 ,表示每个记录输入的时候分隔符.即行与行之间如何分隔.
- NR 即 number of record 记录(行)号,表示当前正在处理的记录(行)的号码
- ORS 即 output record separator 输出记录分隔符
修改RS/修改awk输入显示
测试修改awk的数据输入,行分隔符
测试数据
head -3 yuchao.log
cc01 cc02 cc03 cc04 cc05
cc06 cc07 cc08 cc09 cc10
cc11 cc12 cc13 cc14 cc15
#这个写法,等于awk默认的行分隔符,现在是指定看效果是 \n
awk -v RS='\n' '{print $0}' test_awk.log
cc01 cc02 cc03 cc04 cc05
cc06 cc07 cc08 cc09 cc10
cc11 cc12 cc13 cc14 cc15
cc16 cc17 cc18 cc19 cc20
cc21 cc22 cc23 cc24 cc25
cc26 cc27 cc28 cc29 cc30
cc31 cc32 cc33 cc34 cc35
cc36 cc37 cc38 cc39 cc40
cc41 cc42 cc43 cc44 cc45
cc46 cc47 cc48 cc49 cc50
# 让awk读取该文件,将每一个 cc01 cc02 都单独认为是一行,即以空格作为RS行分隔符
#这里是修改RS行分隔符为空格,awk看到空格就认为是新的一行数据
awk -v RS=' ' '{print $0}' test_awk.log
cc01
cc02
cc03
修改ORS、修改awk动作执行后的数据打印格式
当awk处理完毕后,print打印结果,默认也是 一个换行符
#源数据
cat test_awk.log
cc01 cc02 cc03 cc04 cc05
cc06 cc07 cc08 cc09 cc10
cc11 cc12 cc13 cc14 cc15
cc16 cc17 cc18 cc19 cc20
cc21 cc22 cc23 cc24 cc25
cc26 cc27 cc28 cc29 cc30
cc31 cc32 cc33 cc34 cc35
cc36 cc37 cc38 cc39 cc40
cc41 cc42 cc43 cc44 cc45
cc46 cc47 cc48 cc49 cc50
awk给这个默认打印的结果,结尾加上的是 换行符
你可以修改这个,awk的输出行分隔符,默认是 换行符
把awk输出的行分隔符,改为 @@
修改 ORS变量为@@
awk -v ORS='@@' '{print $0}' test_awk.log
修改ORS/修改awk输出显示
你可以自由修改,awk处理完毕后的每一行的分隔符,也就是修改ORS变量。
小结
awk默认情况下,认为文件从头到尾是一整行数据,直到碰见换行符
bash\n 回车换行符
,因此本行结束,进入下一行
- 可以通过修改awk的RS变量,修改行输入的分隔符
awk列操作(FS操作)
- 行操作
- 列操作
字段(列)
每条记录都是由多个区域(field)组成的
每一行数据,都被分割为了很多个字段
默认情况下区域之间的分隔符是由空格(即空格或制表符)来分隔
将分隔符记录在内置变量 FS中
每行记录的区域数据保存在 awk 的内置变量 NF 中
图解awk字段
FS 即 fileld separator,输入字段(列)分隔符,分隔符就是菜刀,把一行字符串切为很多区域
- bash
FS=':' #看到冒号,就砍一刀,分割为左右两边的数据,注意此时打印就不能用$0了,否则数据还是以逗号分隔的。
NF 即 number of fileds,表示一行中列(字段)的个数,可以理解为菜刀切过一行后,切成了多少份
指定分隔符
当文本不是以空格分割,你得自己找特征,进行切蛋糕。
- FS的值可以是固定的字符、也可以是正则表达式
#例如/etc/passwd文件 ,提取用户信息
#提取出用户名、登录解释器
awk -v FS=':' '{print $1,$NF }' /etc/passwd
# 美化显示的命令column -t
awk -v FS=':' '{print $1,$NF }' /etc/passwd |column -t
提取用户账号密码信息
生成测试数据,python脚本
工作常用的,数据 csv存储
股票.csv
用户信息.csv
如何去提取里面的数据
1.思考,分析该数据的 每一个字段的分隔符是否有特点
2.提取该分隔符,
提取前10位用户的数据
#简单的,读数据,然后awk打印,改为以空格分割每一个数据
test10,123456,583438864691290311
awk -v FS=',' '{print $1,$2,$3}' user_id.csv
#注意,此时打印就不能使用$0了 ,否则结果不变 ,应该使用$1,$2,…… !!!!!!!!
#修改格式为
#身份证号 用户名 密码
awk -v FS=',' '{print $3,$1,$2}' user_id.csv
#身份证号 用户名 密码
cat user1.csv
t1,123,1111111
t2,456,2222222
awk -v FS=',' '{print $3,$2,$1}' user1.csv
1111111 123 t1
2222222 456 t2
awk使用正则
提取30号用户的用户名、身份证号,且显示行号
以身份证号---用户名---密码的格式输出
#数据源
test30,123456,895782891435332651
test90,123456,845590904189307705
test91,123456,631309684235761490
test92,123456,140550391185668516
test93,123456,753107759637368854
test94,123456,572732019383725076
test95,123456,817005865875540475
#awk使用正则的语法
awk '/正则表达式/{action}' user_id.csv
#答案
awk -v FS=',' -v OFS='---' '{print $3,$2,$1}' test3.log
FS和OFS
FS,提取数据时,提取的字段,以什么字符进行切割,分割
OFS,打印数据时,每一个字段之间的分隔符是什么
修改FS和OFS变量
刚才我们练习了
- RS和ORS
- RS、输入记录分隔符,决定awk如何分隔每一行(默认是\n)
- ORS,输出记录分隔符,决定awk如何输出每一行(默认是\n)
- FS和OFS
- FS是输入字段分隔符,决定awk输入数据后的每一个字段分隔符是什么,默认是空格
- OFS是输出字段分隔符,决定awk输出每个字段的分隔符是什么,默认是空格
指定FS分隔符(在哪个位置切蛋糕)
#两个方式
#1、参数
awk -F '分隔符'
#2.修改变量
awk -v FS='分隔符'
当你拿到一个数据文本,并非是很直观的可以看出 空格分割的数据
那么你就得自己找规律,如何提取该数据,也就是指定分隔符,修改FS变量。
测试数据
cat yuchao.log
cc01 cc02 cc03 cc04 cc05
cc06 cc07 cc08 cc09 cc10
cc11 cc12 cc13 cc14 cc15
cc16 cc17 cc18 cc19 cc20
cc21 cc22 cc23 cc24 cc25
cc26 cc27 cc28 cc29 cc30
cc31 cc32 cc33 cc34 cc35
cc36 cc37 cc38 cc39 cc40
cc41 cc42 cc43 cc44 cc45
cc46 cc47 cc48 cc49 cc50
要求修改每一个数据之间的分隔符,改为#号
$1 ,$2 是字段之间的逗号,和OFS对应
awk -v OFS='#' '{print $1,$2,$3,$4,$5}' test_awk.log
cc01#cc02#cc03#cc04#cc05
cc06#cc07#cc08#cc09#cc10
cc11#cc12#cc13#cc14#cc15
cc16#cc17#cc18#cc19#cc20
cc21#cc22#cc23#cc24#cc25
cc26#cc27#cc28#cc29#cc30
cc31#cc32#cc33#cc34#cc35
cc36#cc37#cc38#cc39#cc40
cc41#cc42#cc43#cc44#cc45
cc46#cc47#cc48#cc49#cc50
修改/etc/passwd的格式
修改原本用户信息的冒号分隔符、改为---
提取出 root、家目录、登录解释器
head -5 /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
head -5 /etc/passwd|awk -v FS=':' -v OFS='---' 'NR==1{print $1, $(NF-1),$NF}'
图解修改FS、OFS
awk特殊模式:BEGIN和END用法
BEGIN
- BEGIN模式作用是在awk开始读取文件行数据、之前就先执行,一般用于预定义一些操作,比如数据的表头格式化等。
- BEGIN后面必须跟上action动作
#语法
awk 'BEGIN{print 表头内容} 模式{动作}'
#显示/etc/passwd前五行,并打印“awk正在执行中"表头
awk 'BEGIN{print"awk正在执行中"} NR<=5{print $o}' /etc/passwd
END
- 和BEGIN相反,END就是awk结束后的操作
- END是awk读取完所有的文件后,再执行END模块,一般用来总结、格式化打印一个工 结果
- END仅会在awk所有行数据处理完毕后,执行END动作。
#语法
awk '模式{动作} END{print 结尾内容}'
#提取系统前五个用户的,用户名、uid、gid、家目录、登录解释器、设置为表头且结束后提示,awk已经处理完毕
head -2 /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
awk -v FS=':' 'BEGIN{print "用户名","uid","gid","家目录","登陆解释器"}NR<=5{print $1,$3,$4,$6,$7}END{print "awk已经处理完毕"}' /etc/passwd | column -t
用户名 uid gid 家目录 登陆解释器
root 0 0 /root /bin/bash
bin 1 1 /bin /sbin/nologin
daemon 2 2 /sbin /sbin/nologin
adm 3 4 /var/adm /sbin/nologin
lp 4 7 /var/spool/lpd /sbin/nologin
awk已经处理完毕
总结行、列
- RS、ORS、代表了awk的输入、输出、关于
行
的分隔符 - FS、OFS、代表了awk的输入、输出、关于
列
的分隔符- 对于不同的文本,需要选择合适的FS、合适的菜刀,来分割出左右可以便于提取的数据
- NR表示行号、记录号
- NF表示每一行的字段数、有多少列
- $符号一般用于提取某一列的数据,如$1、$2
- $NF表示最后一列的数据
面试题
awk方法
统计单词出现频率
- 统计下文中出现次数最多的前5个单词
I have a dog, it is lovely, it is called Mimi. Every time I go home from school, Mimi always cruising around me, I will go to the kitchen to get a piece of meat to it, it lay on the floor to eat. My legs and then jump to bark "Wang "called, so I picked up Mimi, it is the opportunity to lick my hand, making me laugh.I like Mimi, like puppies.
思路
- 将一整行的数据,改为,每一个单词,就是一行
- 改为这样后,就可以交给sort去排序了
- 再去uniq 去重 -c 统计重复的次数
#不考虑标点符号的情况
awk -v RS=' ' '{print $0}' english.txt | sort | uniq -c | sort -r | head -5
6 to
6
4 it
3 the
3 is
#显然不统计标点符号的情况,统计结果会不准确,所以可以用正则处理标点符号
#正则表示 除了字母之外的特殊符号都视作换行符,就可以将逗号,句号等和空格划分为一组
#然后再按上述思路解决
awk -v RS='[^a-zA-Z]+' '{print $0}' english.txt | sort | uniq -c | sort -r | head -5
6 to
5 it
5 I
4 Mimi
3 the
sed方法
sed -r 's#[^a-zA-Z]+#\n#g' english.log | sort | uniq -c | sort -r -n | head -5
6 to
5 it
5 I
4 Mimi
3 the
tr方法
tr命令就是将字符替换的作用
基本语法
tr 'old_string' 'new_string'
echo 'hello world' | tr 'll' 'LL'
heLLo worLd
#思路就是将文本中的空格,换为 \n ,就实现了每一个单词,作为新的一行
#但没考虑标点符号
cat english.log | tr ' ' '\n' | sort | uniq -c | sort -r | head -5
6 to
4 it
4 I
3 the
3 is
grep方法
#将所有单词提取出来,处理
grep -E '[a-zA-Z]+' english.log -o | sort | uniq -c | sort -r | head -5
6 to
5 it
5 I
4 Mimi
3 the