文章目录
前言
本文是对shell以及文本三剑客grep、sed、awk进行科普,如果对shell脚步不是非常熟悉的同学,很欢迎仔细读本文。
如果对理论不敢兴趣,可以直接跳到,grep使用实例,sed使用实例,awk使用实例
本文纯原创,感谢支持
一、什么是shell
Shell是命令解释器(command interpreter),是Unix操作系统的用户接口,程序从用户接口得到输入信息,shell将用户程序及其输入翻译成操作系统内核(kernel)能够识别的指令,并且操作系统内核执行完将返回的输出通过shell再呈现给用户
shell脚本
指.sh结尾的脚本
1、一个shell脚本通常包含如下部分:
- (1)、首行
第一行内容在脚本的首行左侧,表示脚本将要调用的shell解释器,内容如下:
#!/bin/bash
- (2)、注释
注释符号# 放在需注释内容的前面,如下:
- (3)、内容
可执行内容和shell结构
2、一个完整的shell脚本
first.sh
#!/bin/bash
# my firest shell
echo "hello world"
3、尝试运行我们第一个shell脚本
1、创建文件夹
mkdir /usr/local/myshell
2、创建文件
vi /usr/local/myshell/first.sh
3、复制我们的shell脚本
4、赋予执行文件权限
chmod +x /usr/local/myshell/first.sh
5、执行文件
/usr/local/myshell/first.sh
6、执行结果
hello world
本文不是主要讲shell脚本,如有兴趣,可以关注下一篇文章
大白话
windows是通过图形界面操作的,而linux是通过shell操作一个个命令的。
二、shell常用操作
ls 列出文件的目录
[root@k8s-master /]# ls
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
cd 进入目录
[root@k8s-master /]# cd usr/local/myshell/
[root@k8s-master myshell]#
ps 查看正在运行软件
[root@k8s-master myshell]# ps -aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.3 0.1 125900 3716 ? Ss 5月07 3:15 /usr/lib/systemd/systemd --switched-root --system --deserialize 22
root 2 0.0 0.0 0 0 ? S 5月07 0:00 [kthreadd]
root 4 0.0 0.0 0 0 ? S< 5月07 0:00 [kworker/0:0H]
root 6 0.0 0.0 0 0 ? S 5月07 0:52 [ksoftirqd/0]
ps 某一个线程,如我查看docker线程
[root@k8s-master myshell]# ps -ef|grep docker
root 1035 1 2 5月07 ? 00:25:57 /usr/bin/dockerd
root 1184 1035 0 5月07 ? 00:03:02 docker-containerd --config /var/run/docker/containerd/containerd.toml
find 查看linux中某一个文件的路径
为了节省时间,最好指定某一个路径,按照名字进行查找
查找路径etc下,名字为password开头的文件
[root@k8s-master myshell]# find /etc -name password*
/etc/openldap/certs/password
/etc/pam.d/password-auth-ac
/etc/pam.d/password-auth
pwd查看当前工作目录
[root@k8s-master myshell]# pwd
/usr/local/myshell
rm 删除文件
mv 移动文件
cp 复制文件
cat 查看文件
vi 编辑文件
如果对shell基本操作有兴趣可以自己百度,下面进入正题,文本处理三剑客,grep、sed、awk
三、文本处理三剑客 — 搜索工具grep
1.什么是grep
Linux系统中grep命令是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来。grep全称是Global Regular Expression Print,表示全局正则表达式版本,它的使用权限是所有用户。
2.格式
grep [options]
3.主要参数
[options]主要参数:
-c:只输出匹配行的计数。
-i:不区分大小写(只适用于单字符)。
-h:查询多文件时不显示文件名。
-l:查询多文件时只输出包含匹配字符的文件名。
-n:显示匹配行及行号。
-s:不显示不存在或无匹配文本的错误信息。
-v:显示不包含匹配文本的所有行。
-w: 完全匹配
4.pattern正则表达式主要参数:
\: 忽略正则表达式中特殊字符的原有含义。
^:匹配正则表达式的开始行。
$: 匹配正则表达式的结束行。
\<:从匹配正则表达式的行开始。
\>:到匹配正则表达式的行结束。
[ ]:单个字符,如[A]即A符合要求 。
[ - ]:范围,如[A-Z],即A、B、C一直到Z都符合要求 。
。:所有的单个字符。
* :有字符,长度可以为0。
5. grep使用实例
本文只介绍一种使用方法,就是如何在复杂的文本中查找出自己想要东西
(1)、直接查找进程, 发现数量实在太多
[root@k8s-master myshell]# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 5月07 ? 00:03:27 /usr/lib/systemd/systemd --switched-root --system --deserialize 22
root 2 0 0 5月07 ? 00:00:00 [kthreadd]
root 4 2 0 5月07 ? 00:00:00 [kworker/0:0H]
root 6 2 0 5月07 ? 00:00:56 [ksoftirqd/0]
。。。
改进,采用grep过滤,把docker进程过滤出来
[root@k8s-master myshell]# ps -ef|grep docker
root 1035 1 2 5月07 ? 00:27:53 /usr/bin/dockerd
root 1184 1035 0 5月07 ? 00:03:14 docker-containerd --config /var/run/docker/containerd/containerd.toml
把java进程过滤出来,发现我没有运行java程序
[root@k8s-master myshell]# ps -ef|grep java
root 92443 66231 0 03:22 pts/0 00:00:00 grep --color=auto java
(2)、为了方便大家理解,我们创建一个文件来进行解释,请大家消化吸收一下参数的意义
cat /usr/local/myshell/greptest
大狗 花色 1岁 5.2斤
小狗 红色 0.8岁 5.3斤
花猫 白色 1.8岁 4.2斤
兔子 黑色 0.7岁 2.3斤
- -c:只输出匹配行的计数。
[root@k8s-master myshell]# cat /usr/local/myshell/greptest | grep -c 狗
2
- -n:显示匹配行及行号。
[root@k8s-master myshell]# cat /usr/local/myshell/greptest | grep -n 花
1:大狗 花色 1岁 5.2斤
3:花猫 白色 1.8岁 4.2斤
- -v:显示不包含匹配文本的所有行。
[root@k8s-master myshell]# cat /usr/local/myshell/greptest | grep -nv 花
2:小狗 红色 0.8岁 5.3斤
4:兔子 黑色 0.7岁 2.3斤
(3)、正则表达式
- ^:匹配正则表达式的开始行。
以大开头的
[root@k8s-master myshell]# cat /usr/local/myshell/greptest | grep ^大
大狗 花色 1岁 5.2斤
- $: 匹配正则表达式的结束行。
[root@k8s-master myshell]# cat /usr/local/myshell/greptest | grep 3斤$
小狗 红色 0.8岁 5.3斤
兔子 黑色 0.7岁 2.3斤
- [ ]:单个字符,如[A]即A符合要求 。
[root@k8s-master myshell]# cat /usr/local/myshell/greptest | grep [花岁]
大狗 花色 1岁 5.2斤
小狗 红色 0.8岁 5.3斤
花猫 白色 1.8岁 4.2斤
兔子 黑色 0.7岁 2.3斤
- [ - ]:范围,如[A-Z],即A、B、C一直到Z都符合要求 。
[root@k8s-master myshell]# cat /usr/local/myshell/greptest | grep [4-6]
大狗 花色 1岁 5.2斤
小狗 红色 0.8岁 5.3斤
花猫 白色 1.8岁 4.2斤
- . :所有的单个字符。
-w: 完全匹配
[root@k8s-master myshell]# cat /usr/local/myshell/greptest | grep -w 1.
大狗 花色 1岁 5.2斤
- *:多个字符,长度大于1个
[root@k8s-master myshell]# cat /usr/local/myshell/greptest | grep -w 1*
花猫 白色 1.8岁 4.2斤
四、文本处理三剑客 — 流编辑器sed
1. 什么是sed
sed是一种流编辑器,它是文本处理中非常重要的工具,能够完美的配合正则表达式使用,功能不同凡响。处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直到文件末尾。文件内容并没有 改变,除非你使用重定向存储输出。Sed主要用来自动编辑一个或多个文件;简化对文件的反复操作;编写转换程序等。
2. sed命令常用参数
常用命令
函数命令 | 说明 |
---|---|
1,n | 需要操作的行,第一行至第N行 |
s | search 查找替换,这个命令使用最多 |
a | append 添加 |
i | insert 插入 |
c | 替换 |
d | 删除行 |
p | 打印 |
还有两个最重要的参数(-n -i)
-
-n 使用安静(silent)模式。在一般 sed 的用法中,所有来自 STDIN 的数据一般都会被列出到终端上。但如果加上 -n 参数后,则只有经过sed 特殊处理的那一行(或者动作)才会被列出来。
-
-i 直接替换原文件,不加-i都不会修改原文件,只是输出或者放置内存中。
3. sed使用实例
以上都是我亲手测试过才写出来,希望读者可以跟我一起写一遍
(1)、当你将 windows 系统中的文件复制到 linux 后,这个文件每行都会以 \r\n 结尾,sed 可以轻易将其转换为 linux 格式的文件,使用\n 结尾的文件:
#filename.sh 需要将\r\n 结尾替换\n结尾
sed -i 's/\r$//' filename.sh
1.授权
[root@k8s-master myshell]# chmod +x filename.sh
2.执行,报错
[root@k8s-master myshell]# ./filename.sh
-bash: ./filename.sh: /bin/bash^M: 坏的解释器: 没有那个文件或目录
[root@k8s-master myshell]#
以上重现了 当你将 windows 系统中的文件复制到 linux 后,这个文件每行都会以 \r\n 结尾,在linux下是无法执行的。
解决方案
[root@k8s-master myshell]# sed -i 's/\r$//' filename.sh
# 运行成功
[root@k8s-master myshell]# ./filename.sh
window下文件和linux区别
(2)、为了方便大家理解,我们创建一个文件来进行解释,请大家消化吸收一下参数的意义
[root@k8s-master myshell]# cat sedtest
111
222
333
444
555
- 输出第3和第5行(p)
[root@k8s-master myshell]# sed -n '3,5p' sedtest
333
444
555
- 输出第3和第5行§,如果不加 -n
[root@k8s-master myshell]# sed '3,5p' sedtest
111
222
333
333
444
444
555
555
- 删除第三至第五行(d), 不修改源文件
[root@k8s-master myshell]# sed '3,5d' sedtest
111
222
- 删除第三至第五行(d), 修改源文件
[root@k8s-master myshell]# sed -i '3,5d' sedtest
[root@k8s-master myshell]# cat sedtest
111
222
- 第二行替换©为 aaa, 修改源文件
[root@k8s-master myshell]# sed -i '2c aaa' sedtest
[root@k8s-master myshell]# cat sedtest
111
aaa
- 第二行之前添加(i)ccc, 修改源文件
[root@k8s-master myshell]# sed -i '2i ccc' sedtest
[root@k8s-master myshell]# cat sedtest
111
ccc
aaa
- 第三行之后添加(a)nnn, 修改源文件
[root@k8s-master myshell]# sed -i '3a nnn' sedtest
[root@k8s-master myshell]# cat sedtest
111
ccc
aaa
nnn
- 第一行替换©为iii, 修改源文件
[root@k8s-master myshell]# sed -i '1c iii' sedtest
[root@k8s-master myshell]# cat sedtest
iii
ccc
aaa
nnn
sed最重要的s命令,查找替换
sed “s/查找/替换/g” g表示一行全部替换,默认一行只替换第一个
9. 将c替换为灿
[root@k8s-master myshell]# sed "s/c/灿/" sedtest
iii
灿cc
aaa
nnn
- 将c全部替换为灿
[root@k8s-master myshell]# sed "s/c/灿/g" sedtest
iii
灿灿灿
aaa
nnn
- 每一行开始加//
[root@k8s-master myshell]# sed "s/^/\/\//g" sedtest
//iii
//ccc
//aaa
//nnn
- 每一行行尾加;
[root@k8s-master myshell]# sed "s/$/;/g" sedtest
iii;
ccc;
aaa;
nnn;
- 替换每一行的第二匹配字符a,替换成+
[root@k8s-master myshell]# sed "s/a/+/2" sedtest
iii
ccc
a+a
nnn
- 把i替换成我,把n替换成帅
[root@k8s-master myshell]# sed "s/i/我/g;s/n/帅/g" sedtest
我我我
ccc
aaa
帅帅帅
五、文本处理三剑客 — 文本分析工具awk
1. 什么是awk
awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大。简单来说awk就是把文件逐行的读入,默认以空格为分隔符将每行切片,切开的部分再进行各种分析处理。 awk是行处理器,相比较屏幕处理的优点,在处理庞大文件时不会出现内存溢出或是处理缓慢的问题,通常用来格式化文本信息
awk处理过程: 依次对每一行进行处理,然后输出
2. awk的用法:
awk 参数 ’ BEGIN{} // {action1;action2} ’ END{} 文件名
参数:
-F 指定分隔符
-f 调用脚本
-v 定义变量
- Begin{} 初始化代码块,在对每一行进行处理之前,初始化代码,主要是引用全局变量,设置FS分隔符
- // 匹配代码块,可以是字符串或正则表达式
- {} 命令代码块,包含一条或多条命令,多条命令用 ; 隔开
- END{} 结尾代码块,在对每一行进行处理之后再执行的代码块,主要是进行最终计算或输出结尾摘要信息
案例: 统计 /etc/passwd 文件中包含root行的总数
root@k8s-master etc]# awk 'BEGIN{X=0}/root/{X+=1}END{print "I find",X,"root lines"}' /etc/passwd
I find 2 root lines
3. awk中字符的含义:
$0 | 表示整个当前行 |
---|---|
$1 | 每行第一个字段 |
NF | 字段数量变量 |
NR | 每行的记录号,多文件记录递增 |
FNR | 与NR类似,不过多文件记录不递增,每个文件都从1开始 |
\t | 制表符 |
\n | 换行符 |
FS | BEGIN时定义分隔符 |
RS | 输入的记录分隔符, 默认为换行符(即文本是按一行一行输入) |
~ | 包含 |
!~ | 不包含 |
== | 等于,必须全部相等,精确比较 |
!= | 不等于,精确比较 |
&& | 逻辑与 |
+ | 匹配时表示1个或1个以上 |
/[0-9][0-9]+/ | 两个或两个以上数字 |
/[0-9][0-9]*/ | 一个或一个以上数字 |
OFS | 输出字段分隔符, 默认也是空格,可以改为其他的 |
ORS | 输出的记录分隔符,默认为换行符,即处理结果也是一行一行输出到屏幕 |
-F [:#/] | 定义了三个分隔符 |
4. awk使用实例
(1)把当前网卡地址都打印出来
[root@k8s-master etc]# ifconfig | awk '{if($1=="inet")print $2}'
10.244.0.1
172.17.0.1
192.168.102.11
10.244.0.0
127.0.0.1
由以上的分析
$1 代表第一行, 等于inet, 输出第二行
(2) 为了掩饰方便,我选择了使用 /etc/passwd 这个文件来给大家进行演示
- 以:分割,输出 第一行
[root@k8s-master ~]# awk -F: '{print $1}' /etc/passwd
root
bin
daemon
adm
lp
。。。
- 以:分割,输出 第一行 和 第二行
[root@k8s-master ~]# awk -F: '{print $1 $2}' /etc/passwd
rootx
binx
daemonx
admx
lpx
。。。
- 以:分割, 输出第一、三、六行, 制表符为tab
[root@k8s-master ~]# awk -F: '{print $1,$3,$6}' OFS="\t" /etc/passwd
root 0 /root
bin 1 /bin
daemon 2 /sbin
adm 3 /var/adm
lp 4 /var/spool/lpd
。。。
- 以: 分割, 输出第一、二行, 分行输出
[root@k8s-master ~]# awk -F: '{print $1; print $2}' /etc/passwd
root
x
bin
x
daemon
x
。。。
- 显示每行有多少字段
[root@k8s-master ~]# awk -F: '{print NF}' /etc/passwd
7
7
7
7
7
。。。
- 打印行数等于5的
[root@k8s-master ~]# awk -F: 'NR==5{print}' /etc/passwd
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
- 将输出到控制台的数据打印成txt
[root@k8s-master ~]# awk -F: '{print}' /etc/passwd > awktest.txt
[root@k8s-master ~]# ls
1.txt anaconda-ks.cfg awktest.txt first.sh flannel-v0.11.0-amd64 logs wr
[root@k8s-master ~]# cat awktest.txt
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
。。。
- 打印出含有root的行
[root@k8s-master ~]# awk -F: '/root/{print }' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
- 打印出文件含有root的行
[root@k8s-master ~]# awk -F: '($1=="root"){print}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
- 打印出文件中第一个字段是root或ftp的行,与上面的等效
[root@k8s-master ~]# awk -F: '($1=="root"||$1=="ftp"){print}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
- 如果第一个字段是mail,则打印第一个字段,否则打印第2个字段
[root@k8s-master ~]# awk -F: '{if($1~/mail/) {print $1} else {print $2}}' /etc/passwd
x
x
x
x
x
x
x
x
mail
x
x
x
x
x
x
x
x
x
x
- 采用 ps -ef 做为例子继续举例
- 打印出开头为非root的行
[root@k8s-master ~]# ps -ef | awk '$1!="root" {print}'
UID PID PPID C STIME TTY TIME CMD
polkitd 769 1 0 5月07 ? 00:00:38 /usr/lib/polkit-1/polkitd --no-debug
chrony 773 1 0 5月07 ? 00:00:00 /usr/sbin/chronyd
dbus 784 1 0 5月07 ? 00:08:12 /usr/bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation
postfix 1227 1221 0 5月07 ? 00:00:00 qmgr -l -t unix -u
postfix 2343 1221 0 11:07 ? 00:00:00 pickup -l -t unix -u
- 打印出进程PID大于100000的行数
[root@k8s-master ~]# ps -ef | awk '$2>100000 {print}'
UID PID PPID C STIME TTY TIME CMD
root 100167 2 0 10:54 ? 00:00:00 [kworker/3:2]
root 105069 2 0 10:56 ? 00:00:00 [kworker/u256:2]
- 只打印UID和PID,而且用:连接
[root@k8s-master ~]# ps -ef | awk '{print $1":"$2}'
UID:PID
root:1
root:2
root:4
root:6
root:7
root:8
- 各个文件分别计数,行号
[root@k8s-master ~]# ps -ef | awk '{print FNR,$0}'
1 UID PID PPID C STIME TTY TIME CMD
2 root 1 0 0 5月07 ? 00:04:58 /usr/lib/systemd/systemd --switched-root --system --deserialize 22
3 root 2 0 0 5月07 ? 00:00:00 [kthreadd]
4 root 4 2 0 5月07 ? 00:00:00 [kworker/0:0H]
5 root 6 2 0 5月07 ? 00:01:14 [ksoftirqd/0]
6 root 7 2 0 5月07 ? 00:00:04 [migration/0]
7 root 8 2 0 5月07 ? 00:00:00 [rcu_bh]
8 root 9 2 0 5月07 ? 00:07:13 [rcu_sched]
9 root 10 2 0 5月07 ? 00:00:00 [lru-add-drain]
六、作者有话要说
关于shell、文本处理三剑客grep sed awk,学习的唯一途径,就是多写,先学习基本的用法,然后根据自己的想法,就可以产生无限的可能
本人长期从事java后台开发,如果有疑问请在下方评论,看到就会及时回复
上一篇文章:java8新特性lambda和Stream新手springboot案例2020年新版
大部分的程序员,都是面向百度或者谷歌进行编程的,而网上的资料乱七八糟,有时候找起来让人难受,于是本人无偿进行资料收集的工作,大部分资料都是本人实打实收集的而且测试过,大家不用怀疑准确性,奈何能力有限,免于遗漏,希望读者可以在评论或者私信我,进行改正,大家一起为互联网技术做贡献。
收集资料枯燥无味,如果本文对你有帮助,可以点个赞,这个也是对我最大的鼓励和赞许。