Linux正则表达式以及三剑客 grep
、awk
、sed
等命令
首先说为什么要学习这些东西呢?因为正则表达式和这三个命令功能太强大了,如果你要做一个运维人员,必须要完全掌握这三个命令,并且会熟练使用,才能让你的操作更加简单、高效,而作为普通使用Linux系统的人,正则表达式还是需要掌握的,因为每个语言都会有正则表达式,足以见得其重要性,而学习 grep
、awk
、sed
这三个命令也会让你再使用Linux 系统的时候游刃有余,更加高效。接下来让我们开始吧
下文中命令的-v(查看版本)
、-h(帮助)
这种通用选项就不做过多介绍了
1、正则表达式和通配符
为什么要先说正则表达式呢,因为后文的grep
、sed
、awk
三种命令都是需要正则表达式的配合才可以发挥出其强大的功能。那就开始吧:
(1)正则表达式,在使用grep
的时候需要grep -E
或者egrep
来进行调用
表达式 | 含义 | 实例 |
^ | ^字符串,表示匹配以此字符串开头的一行 | ^a:匹配以a开头的行 |
$ | 字符串$,表示匹配以此字符串结尾的一行 | abc$:匹配以abc结尾的行 |
^$ | 表示空行 | |
. | 代表且只能代表任意一个字符 | a.c:表示a和c中间有一个字符 |
\ | 转义符号,让有着特殊的字符显示本身,或者产生其他意思(元字符) | \.:表示匹配点;\$表示匹配$ |
* | 匹配0个或多个前面一个字符 | a*:有0个a或任意个aaaaaa |
? | 匹配0个或1个前面一个字符 | a?:有0个a或1个a |
+ | 匹配至少1个前面的字符 | a+:至少有1个a |
.* | 匹配所有字符 | ^.*:表示以任意多个字符开头;.*$,表示以任意多个字符结尾 |
[abc] | 匹配字符集合内的任意一个字符(单个字符而不是包含的单词) | [a-z]:表示匹配小写字母;[a-zA-Z]:表示匹配所有字母 |
[^abc] | 匹配不包含^后的任意一个字符的内容(单个字符而不是包含的单词),上一行的去反像;其中括号里^此处为取反,注意和中括号内以^开头区别 | [^0-9]:表示不匹配数字 |
a{m,n} | a连续出现的次数大于m次,小于n次,可以不写m或者n(逗号要写),意思应该都懂吧 | [abc]{2,}:表示连着的至少两个字符都是a或b或c |
a{n} | a连续出现n次,多了少了都不算 | [abc]{3}:表示连着三个字符都是a或b或c |
| | 或,左右两边匹配到一个即可 | ab|bc:表示ab或bc有一个匹配到即可 |
() | 表示分组过滤 | a(b|d)c:表示要匹配abc或者adc |
(2)元字符,在正则中使用
表达式 | 含义 |
\b | 单词边界,比如\ba,能够匹配到以a开头的单词;\ba\b,只能够匹配到单词a |
\B | 非单词边界,上面反之 |
\d | 单个数字字符,其和[0-9]也是有很大的区别的,推荐使用[0-9],\d可能无法达到预期结果 |
\D | 单个非数字字符,上面反之 |
\w | 单个单词字符(字母,数字与_),比如\w{6,10},能够匹配到一个简单的密码 |
\W | 单个非单词字符,上面反之 |
\s | 单个空白字符,普通空格、tab键(\t)都可以匹配到 |
\S | 单个非空白字符,上面反之 |
\n | 换行符 |
\r | 回车 |
\t | 横向制表符 |
\v | 垂直制表符 |
\f | 换页符 |
(3)通配符,文件名、普通命令都可以使用
通配符 | 含义 |
. | 当前目录 |
… | 两个点代表上一级目录 |
* | 通配符,代表所有(0到多个)字符,例如“*.txt”,找出所有的txt文件 |
? | 通配符,代表1个字符,例如“???.txt”,找出名字是4个字符的txt文件 |
~ | 当前用户的home目录 |
- | 上一次所在的目录(路径),cd命令之前的目录 |
/ | 路径分隔符号,也是根目录的意思 |
; | 连续不同命令的分隔符(两个命令的分隔符) |
# | 配置文件注释(就是让其命令失效,但可以给管理员看到) |
| | 管道 |
$ | 变量前需要加的符号,例如“echo $LANG”,可以打印出当前命令窗口的字符集 |
>> | 追加重定向,追加内容文件尾部 |
<< | 追加输入重定向 |
` | tab键上面的键,反引号,两个``中间的命令,会先执行 |
(4)简单举个例子吧:
① 匹配ip地址:^([0-9]{1,3}\.){3}[0-9]{1,3}$ # 以数字显示1-3次,然后是点循环3次开头,再数字显示1-3次结尾。
2、grep
命令
(1)其语法格式
grep [选项] "正则字符串" 文件目录
当然,[选项]
也可以放到命令的最后
(2)其中[选项]
的参数可以是
选项 | 作用意义 |
-r | 当文件目录参数是文件夹时,必须使用该选项,用来遍历文件夹下的所有文件 |
-n | 输出时显示行号 |
-v | 反向,输出匹配到的行以外的行,即输出所有不匹配的行 |
-c | 只输出匹配到的行数 |
-i | 忽略大小写 |
-l | 输出所有匹配到字符串的的文件名 |
-x | 完全匹配字符串,空格不匹配也不行 |
-A数字 | 显示匹配到的行以及这行后面的n行(n即是你写的数字,此数字必写,可以为0) |
-B数字 | 显示匹配到的行以及这行前面的n行(n即是你写的数字,此数字必写,可以为0) |
-C数字 | 显示匹配到的行以及这行前后的n行(n即是你写的数字,此数字必写,可以为0) |
(3)这个命令并不难(其格式就是上面这种比较固定),但我们还是来举个例子吧
先来准备个文件吧:
wtq@wtq[~]$ cat -n test.txt
1 #!/bin/sh
2 # 读取文件最后一行的四种方式
3 # cat suv.mnc | awk 'END {print}'
4 # cat 343/asd/kbc/text.txt | sed -n '$p'
5 # cat /home/wtq/asd.mnc | sed '$!N;$!D'
6 # cat bbb.suv | awk '{b=a"\n"$0;a=$0}END{print b}'
7 #sudo dpkg-reconfigure dashsh end
① 找到包含“end”的行,忽略其大小写,并显示行号:
wtq@wtq[~]$ grep -in "end" test.txt # n表示输出行号,i表示忽略大小写
3:# cat suv.mnc | awk 'END {print}'
6:# cat bbb.suv | awk '{b=a"\n"$0;a=$0}END{print b}'
7:#sudo dpkg-reconfigure dashsh end
② 不包含“cat”的行,只显示其行数:
wtq@wtq[~]$ grep "cat" test.txt -v # 选项也可以放在结尾,v表示反转,不包含
#!/bin/sh
# 读取文件最后一行的四种方式
#sudo dpkg-reconfigure dashsh end
wtq@wtq[~]$ grep "cat" test.txt -vc # c表示只输出结果的总行数
3
③ 用正则进行搜索:
先来匹配出宝行“d”、“k”,中间有且只有一个随意字符的行:
wtq@wtq[~]$ grep -n "d.k" test.txt # 不使用-E的时候, .表示通配符,匹配任意一个字符
4:# cat 343/asd/kbc/text.txt | sed -n '$p'
7:#sudo dpkg-reconfigure dashsh end
再来匹配出“ }‘ ”结尾的行,显示其行号
wtq@wtq[~]$ grep -nE "}'$" test.txt # $表示以什么结尾
3:# cat suv.mnc | awk 'END {print}'
6:# cat bbb.suv | awk '{b=a"\n"$0;a=$0}END{print b}'
④ 遍历SDK目录下,找出其所有的“config”:
wtq@wtq[~/Android/Sdk]$ grep "config" ./ -rn # 由于结果太多我就不输出了,大家可以自己试一下
其他的:
1、egrep
命令
其用法同grep -E
,egrep
是用extended regular expression(拓展的正则表达式)
语法来解读的,而grep
则用basic regular expression(基本的正则表达式子)
语法解读,extended regular expression
比basic regular expression
的表达更规范。
2、fgrep
命令
其用法同grep -F
,可以当作是其的简写,不常用。
3、rgrep
命令
用于递归查找文件夹下所有的子文件中符合条件的字符串,同grep -r
。
3、sed
命令
(1)其语法格式为
sed [选项] [脚本/脚本文件] 文本文件
当然,[选项]
也可以放到命令的最后
其中[选项]
的参数可以是
选项 | 作用意义 |
-e | 表示第三个位置跟的是脚本命令,可以写多个(一般情况下可以省略) |
-f | 表示第三个位置跟的是脚本文件 |
-n | 表示只显示脚本处理之后的结果,不写的会把全部内容打印一次,而搜索结果的行会显示两行 |
-i | 直接修改文件内容 |
(2)那脚本怎么写呢?
① "/正则表达式/ 动作"
② "行号m,行号n 动作"
③ sed "s/要被取代的字串/新的字串/g"
我们一种一种来说啊
①第一种和第二种这里面的动作是什么?
动作 | 作用意义 |
行号a字符串 | a表示append,表示在你输入的行号n的下一行插入一句字符串 |
行号i字符串 | i表示insert,表示在你输入的行号n的上一行插入一句字符串 |
c字符串 | c表示change,表示将匹配到的(一般在2中使用) |
d | d表示delete,删除匹配到的行 |
p | p表示print,打印匹配到的行,一般与-n配合 |
s | s表示search&replace,表示搜索出匹配的字符串并且将之替换(一般在③中使用) |
g | g表示global,g 代表全部替代匹配到的内容(一般在③中使用) |
②其实第一种和第二种差不多,只是第一种正则只能一行一行的匹配其中内容,而第二种可以从m行到n行一起进行处理,所以在会使用第一种就会使用第二种了。这两种都是针对行进行处理,匹配到的结果都是包含这个字符串的一整行。
③除了整行的处理模式之外, sed
还可以用行为单位进行部分数据的搜寻并取代。而这第三种就是针对部分数据进行搜索替换,意为匹配到的字符串后,使用新的字符串将之替换,不会修改文件内容,只会替换显示结果。因此我们可以结合前两种方式,在选择的行中替换匹配到的字符串。
(3)上述说了这么多,大家肯定也是一脸懵,说再多也没有举例子来的真实,接下来就是举例子环节了。
首先我们准备一个文件:
wtq@wtq[~]$ cat test.txt -n
1 auu
2 aeeeeeee
3 se
4 sdddd
5 ooaekkaemmae+
6 kka
7 aeaekk
① 在第四行后面加一个”ashdjk“,为了方便显示我就使用另一种方式了:
wtq@wtq[~]$ cat test.txt -n | sed "4a ashdjk" # 4表示第四行,a表示第四行之后添加,空格之后的字符串表示要添加的字符串
1 auu
2 aeeeeeee
3 se
4 sdddd
ashdjk
5 ooaekkaemmae+
6 kka
7 aeaekk
那在第四行之后,其用法都是一样的,大家可以自行练习试用一下(比如再第五行之前插入”welcome you!“)
② 删除3至5行的内容:
wtq@wtq[~]$ cat test.txt -n | sed "3,5d" # m,n表示从3行到5行的内容,d表示删除
1 auu
2 aeeeeeee
6 kka
7 aeaekk
那删除3行以后的内容呢,我从不能去数一数总共有几行吧:
wtq@wtq[~]$ cat test.txt -n | sed "3,$ d" # $表示结尾,为了避免$与d产生问题,因此中间加个空格
1 auu
2 aeeeeeee
(那我想删除3行以前的内容,应该怎么做呢?)
③ 找到所有”ae“字符串,将之替换为”new“:
wtq@wtq[~]$ cat test.txt -n | sed "/ae/c new"
1 auu
new
3 se
4 sdddd
new
6 kka
new
当我们使用第一种脚本的c
的时候,发现其替换了包含这个字符串的整行。前文也说了,第一、二种脚本都是针对行进行处理,而且c
更多的时候使用在第二种脚本之中。因此我们应该使用第三种脚本方式才行完成这个功能:
wtq@wtq[~]$ cat test.txt -n | sed "s/ae/new/g" # s表示搜索替换,前一个//表示需要搜索的字符串,后一个//表示需要替换为的字符串,g表示全局搜索
1 auu
2 neweeeeee
3 se
4 sdddd
5 oonewkknewmmnew+
6 kka
7 newnewkk
(那将第2行至第3行替换为”i an boy“,应该怎么写呢?)
④ 只打印出3行至5行的内容:
wtq@wtq[~]$ cat test.txt -n | sed "3,5 p" # p表示打印
1 auu
2 aeeeeeee
3 se
3 se
4 sdddd
4 sdddd
5 ooaekkaemmae+
5 ooaekkaemmae+
6 kka
7 aeaekk
并没有打印出我们想要的结果,它全部打印了一遍,只是把3行至5行多打印了一次,值得注意的是,这个p需要配合-n
使用,才能打印出我们想要的效果:
wtq@wtq[~]$ cat test.txt -n | sed -n "3,5 p" # -n表示只打印匹配到的结果
3 se
4 sdddd
5 ooaekkaemmae+
(那只打印所有具有”ae“的行,应该怎么写呢?)
⑤ 替换5行至6行中共的”kk“,将之替换为”new“:
wtq@wtq[~]$ cat test.txt -n | sed "5,6{s/kk/new/g}" # 这是一个组合操作,找到5行和6行之后是一个组合操作,不是单一的p或者d等等,因此需要使用{},其中进行替换操作
1 auu
2 aeeeeeee
3 se
4 sdddd
5 ooaenewaemmae+
6 newa
7 aeaekk #第七行的kk并未替换
⑥ /sbin/ifconfig
命令可以获取到本地得IP地址,其中inet addr:
就是本机的地址,我们可以通过sed命令来只输出本机的地址:
wtq@wtq[~]/sbin/ifconfig
enp0s31f6 Link encap:Ethernet HWaddr 30:9c:23:77:5f:ed
inet addr:192.168.0.109 Bcast:192.168.0.255 Mask:255.255.255.0
inet6 addr: fe80::b060:e7f5:b451:e814/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:2046238 errors:0 dropped:0 overruns:0 frame:0
TX packets:712812 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:1260925614 (1.2 GB) TX bytes:121332377 (121.3 MB)
Interrupt:16 Memory:f7100000-f7120000
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:44336 errors:0 dropped:0 overruns:0 frame:0
TX packets:44336 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:10535833 (10.5 MB) TX bytes:10535833 (10.5 MB)
wtq@wtq[~]$ /sbin/ifconfig | sed -n "/inet addr/p" | sed -n "1p" | sed "s/^.*addr://g" | sed "s/ Bcast.*$//g" #第一次找出包含"inet addr"的行;第二次筛去127.0.0.1的地址;第三次将"开头到addr:"替换为"",即删除;第四次将 "Bcast到结尾"的字符串删除
192.168.0.109
⑦ 修改文件,删除第一行的内容:
wtq@wtq[~]$ sed -i "1,1d" test.txt # -i表示修改文件内容(不建议使用)
wtq@wtq[~]$ cat -n test.txt
1 aeeeeeee
2 se
3 sdddd
4 ooaekkaemmae+
5 kka
6 aeaekk
⑧ 最后来一个看起来比较复杂但其实相对简单的: df -h
可以查看本机的磁盘容量,查找出其中的"/dev/"开头的行,整行替换为”this is new line“
wtq@wtq[~]$ df -h
Filesystem Size Used Avail Use% Mounted on
udev 7.8G 0 7.8G 0% /dev
tmpfs 1.6G 9.6M 1.6G 1% /run
/dev/nvme0n1p1 46G 5.9G 38G 14% /
tmpfs 7.8G 2.0M 7.8G 1% /dev/shm
tmpfs 5.0M 4.0K 5.0M 1% /run/lock
tmpfs 7.8G 0 7.8G 0% /sys/fs/cgroup
/dev/nvme0n1p6 4.5G 147M 4.1G 4% /boot
/dev/nvme0n1p7 390G 61G 309G 17% /home
/dev/sda1 1.8T 932G 809G 54% /mnt/disk2
tmpfs 1.6G 80K 1.6G 1% /run/user/1000
wtq@wtq[~]$ df -h | sed "/^\/dev\//c this is new line" # 这次就自己分析一下怎么实现的吧
Filesystem Size Used Avail Use% Mounted on
udev 7.8G 0 7.8G 0% /dev
tmpfs 1.6G 9.6M 1.6G 1% /run
this is new line
tmpfs 7.8G 1.9M 7.8G 1% /dev/shm
tmpfs 5.0M 4.0K 5.0M 1% /run/lock
tmpfs 7.8G 0 7.8G 0% /sys/fs/cgroup
this is new line
this is new line
this is new line
tmpfs 1.6G 80K 1.6G 1% /run/user/1000
4、awk
命令
最后这个命令相较于上面两个是比较难的一个。对于awk
命令,我在网上也找了很多,很多自己写的不全面也不 易懂,本文主要参照菜鸟教程中对这个命令的描述来进行讲解,通过阅读其资料,来参照自己的方式,来进行阐述。这个命令主要作用是循环遍历每一行数据,对每一行,先使用分隔符(默认空格)进行切分成列,再对列进行处理。使用此命令需要先掌握print命令,其中printf
类似于C语言中的printf
。当然,下文在使用print命令的时候,也会给大家注释
(1)其语法格式为:
awk [选项] [脚本/脚本文件] 文本文件
其中脚本的格式为(其中选项、begin{}、end{}、文本文件等部分不需要的时候都可以省略):
BEGIN { 循环所有行之前的处理(变量的声明) }
{ 循环处理每一行的命令 }
END { 循环所有行之后的处理事情 }
(2)都有哪些选项呢(这里列举一些比较常用的)?
选项 | 作用意义 |
-F分割符 | 指定分隔符,可以使用多个分隔符,”-F [多个分隔符]“,越靠前的分隔符优先级越高 |
-v 变量=值 | 给变量赋值,可以加多个-v来给多个变量赋值 |
-f | 读取脚本文件 |
(3)接下来就匆匆的进入例子环节了,有什么补充的在例子中进行补充了(_)。
按照惯例,我们先准备一个文件:
wtq@wtq[~]$ cat test.txt #这里不打印行号了,因为行号不重要,awk命令是会循环处理每一行
number this is a apple
50 This's a dog
20 a,b,c asd
jh,adf sd dsa
21 asdkj asd, asd
10 adfds'daf,abc
① 使用空格分割,显示第1列和第3列:
wtq@wtq[~]$ awk '{print $1,$3}' test.txt # 注意,这里不能使用双引号,默认分隔符是空格,因此可以不写,而"$数字"表示第几列
number is
50 a
20 asd
jh,adf dsa
21 asd,
10 # 由于最后一行用空格分割只有两列,因此第三列为空
那想使用”,“进行分割呢?显示第1列和第2列,然后我们为了方便显示观看,我们使用格式进行输出:
wtq@wtq[~]$ cat test.txt | awk -F, '{printf "%-25s %-15s\n",$1,$2}' # 使用-F就可以指定分割符了,printf的格式中,%s表示显示字符串,中间的-表示居左,数字25和15表示总共占多少个字符,需要注意的是%和$的数量要对应(和C语言的printf是一样的)
number this is a apple
50 This's a dog
20 a b
jh adf sd dsa
21 asdkj asd asd # 这个分割以后asd前面还有个空格,因此会比较突出
10 adfds'daf abc
再来,我想用空格和”,“两种进行分割呢?显示第1列和第2列:
wtq@wtq[~]$ awk -F '[ ,]' '{printf "%-10s %15s\n",$1,$2}' test.txt #自己分析一下现象产生的原因吧
number this
50 This's
20 a
jh adf
21 asdkj
10 adfds'daf
② 使用空格分割,设置默认值a=1,我想显示第一列、第一列的值都加上这个默认值以及第三列:
wtq@wtq[~]$ awk -va=1 '{printf "%-10s %-4d %-10s\n",$1,$1+1,$3}' test.txt # -v用来设置默认值,后面加表达式,因此在后面的printf种可以直接使用a,,,%d表示数字
number 1 is # 当值为字符串时,其值相当于0,再进行加法运算
50 51 a # 当值为数字时,则直接进行加法运算
20 21 asd
jh,adf 1 dsa
21 22 asd,
10 11
同样的,使用空格分割,设置默认值a=1,b=2, s=s,我只想显示第一列+s和a+b:
wtq@wtq[~]$ awk -va=1 -vb=2 -vs=s '{printf "%-25s %d\n",$1s,a+b}' test.txt
numbers 3
50s 3
20s 3
jh,adfs 3
21s 3
10s 3
如果开始不赋值,其都默认值,$1+a的时候,a默认为0,$1a的时候,a默认为”“,因此不赋值也不会报错,你懂了吗?
③ 接下来就是运算符了,运算符大家应该用的比较多了,各个语言的运算符基本上都相同,这里列举几个不同的需要注意的吧
运算符 | 描述 |
+、-、*、/、%、=、+=、-=、*=、/=、%=、^=、**=、++、–、<、<=、>、>=、!=、==、&&、||、!、 | 常用运算,不做描述 |
~ 和 !~ | 匹配正则表达式和不匹配正则表达式 |
?: | 三元运算符,if?a:b,if为真返回a,表示if为假返回b |
空格 | 连接 |
^ *** | 求幂 |
$ | 字段引用 |
in | 数组成员,a in b,表示a是否是b的一部分 |
其实不难看出大部分都比较常用的,需要记得也没几个。那我们看看怎么用吧
默认分割的列,找出第一列大于20的:
wtq@wtq[~]$ awk '$1>20' test.txt
number this is a apple # 不难看出字符串不参与比较,直接显示
50 This's a dog
jh,adf sd dsa
21 asdkj asd, asd
默认分割的列,找出第一列大于20的,只显示第一行和第三行:
wtq@wtq[~]$ awk '$1>20 {print $1,$3}' test.txt # 很简单吧
number is
50 a
jh,adf dsa
21 asd,
④ 先来把脚本的格式来阐述一下:
wtq@wtq[~]$ awk 'BEGIN{ print "--------------" }{printf "%-10s %-10s\n",$2,$3} END{print "--------------"}' test.txt # 三个中括号,表示三个节点,注意:BEGIN和END必须要写,不写你试试会发生什么?
--------------
this is
This's a
a,b,c asd
sd dsa
asdkj asd,
adfds'daf,abc
--------------
我们也可以把这个脚本写到一个文件(文件后缀类型随意)中,脚本可以写成多行,方便自己阅读,通过-f来调用脚本文件,使得更方便:
wtq@wtq[~]$ cat aaa.txt #其中的格式自己可以调整,不必只显示一行,方便自己阅读
BEGIN{ print "--------------" }
{printf "%-10s %-10s\n",$2,$3}
END{print "--------------"}
wtq@wtq[~]$ awk -f aaa.txt test.txt # 更简洁明了
--------------
this is
This's a
a,b,c asd
sd dsa
asdkj asd,
adfds'daf,abc
--------------
⑤ 接下来是内建变量,就是不需要使用-v去声明的变量
变量 | 描述 |
$0 | 完整的输入记录 |
ARGC | 命令行参数的数目 |
ARGIND | 命令行中当前文件的位置(从0开始算) |
ARGV | 包含命令行参数的数组 |
CONVFMT | 数字转换格式(默认值为%.6g)ENVIRON环境变量关联数组 |
ERRNO | 最后一个系统错误的描述 |
FIELDWIDTHS | 字段宽度列表(用空格键分隔) |
FILENAME | 当前文件名 |
FNR | 各文件分别计数的行号 |
FS | 字段分隔符(默认是任何空格) |
IGNORECASE | 如果为真,则进行忽略大小写的匹配 |
NF | 一条记录的字段的数目 |
NR | 已经读出的记录数,就是行号,从1开始 |
OFMT | 数字的输出格式(默认值是%.6g) |
OFS | 输出记录分隔符(输出换行符),输出时用指定的符号代替换行符 |
ORS | 输出记录分隔符(默认值是一个换行符) |
RLENGTH | 由match函数所匹配的字符串的长度 |
RS | 记录分隔符(默认是一个换行符) |
RSTART | 由match函数所匹配的字符串的第一个位置 |
SUBSEP | 数组下标分隔符(默认值是/034) |
来用一下吧:
wtq@wtq[~]$ awk 'BEGIN{printf "%4s %4s %4s %4s %4s %4s %4s %4s %4s\n","FILENAME","ARGC","FNR","FS","NF","NR","OFS","ORS","RS";printf "---------------------------------------------\n"} {printf "%4s %4s %4s %4s %4s %4s %4s %4s %4s\n",FILENAME,ARGC,FNR,FS,NF,NR,OFS,ORS,RS}' test.txt
FILENAME ARGC FNR FS NF NR OFS ORS RS # OFS默认为空格,ORS、RS默认为换行,因此会有两个空行,这些内建变量的意思自己看吧
---------------------------------------------
test.txt 2 1 5 1
test.txt 2 2 4 2
test.txt 2 3 3 3
test.txt 2 4 3 4
test.txt 2 5 4 5
test.txt 2 6 2 6
使用空格分割,显示行号、第1列和第3列,其输出使用"_"进行分割:
wtq@wtq[~]$ awk '{print FNR,$1,$3}' OFS="_" test.txt # 这个还是比较简单吧
1_number_is
2_50_a
3_20_asd
4_jh,adf_dsa
5_21_asd,
6_10_
⑥ 接下来就正则了,不使用正则表达式,命令都没有灵魂,哈哈哈哈
先来找一下默认分割下,第2列中含有ad的行,显示行号、第2列和第3列
wtq@wtq[~]$ awk '$2 ~ /ad/ {print FNR,$2,$3}' test.txt
6 adfds'daf,abc
这个例子不好用正则,也之前也用了那么多的正则,大家自己练习一下吧
⑦ 最后来一个比较有趣的例子吧,seq
命令可以打印连续数字,seq 9
可以打印出1到9的数字,因此我们使用它来打印九九乘法表
wtq@wtq[~]$ seq 9 | sed 'H;g' | awk -v RS='' '{for(i=1;i<=NF;i++)printf("%dx%d=%d%s", i, NR, i*NR, i==NR?"\n":"\t")}' # 大家可以自行分析一下,(其实sed 'H;g'我也还没搞懂)
1x1=1
1x2=2 2x2=4
1x3=3 2x3=6 3x3=9
1x4=4 2x4=8 3x4=12 4x4=16
1x5=5 2x5=10 3x5=15 4x5=20 5x5=25
1x6=6 2x6=12 3x6=18 4x6=24 5x6=30 6x6=36
1x7=7 2x7=14 3x7=21 4x7=28 5x7=35 6x7=42 7x7=49
1x8=8 2x8=16 3x8=24 4x8=32 5x8=40 6x8=48 7x8=56 8x8=64
1x9=9 2x9=18 3x9=27 4x9=36 5x9=45 6x9=54 7x9=63 8x9=72 9x9=81
Linux 正则表达式以及三剑客 grep
、awk
、sed
等命令,目前就收罗这么多,当发现新的内容的时候