1、特殊符号

1.1 引号系列

双引号(’ ‘)、单引号(” “)、反引号(“)、不加引号

单引号:所见即所得,单引号里面的内容会原封不动地输出
双引号:和单引号类似,对双引号里面的特殊符号会进行解析,对于{}(通配符)不解析
不加引号:和双引号类似,额外支持通配符(匹配文件),如:*.log{1..10}
反引号:优先执行,先执行反引号里面的命令

单引号:

[root@linux-87-01 ~]# echo 'hello'
hello
[root@linux-87-01 ~]# echo '`hostname`'
`hostname`
[root@linux-87-01 ~]# echo '$UID'
$UID
[root@linux-87-01 ~]# 

双引号:

[root@linux-87-01 ~]# echo "{1..5}"
{1..5}
[root@linux-87-01 ~]# echo "$(whoami)"
root
[root@linux-87-01 ~]# echo "$UID"
0
[root@linux-87-01 ~]# 

反引号、不加引号:

[root@linux-87-01 ~]# echo `hostname`
linux-87-01
[root@linux-87-01 ~]# echo {1..3}.txt
1.txt 2.txt 3.txt
1.2 重定向符号

重定向符号:>、>>

> :其实是1>,一般可以省略1(1:数字1)。正确的标准输出重定向
>>:其实是1>>,一般可以省略1。正确的标准追加输出重定向

2>:错误输出重定向
2>>:错误输出追加重定向

例如:

[root@linux-87-01 ~]# echo 11 > 1.txt
[root@linux-87-01 ~]# echo 22 >> 1.txt
[root@linux-87-01 ~]# cat 1.txt
11
22
[root@linux-87-01 ~]# 

错误输出:

[root@linux-87-01 ~]# hah 2> 1.txt
[root@linux-87-01 ~]# cat 1.txt
-bash: hah: command not found
[root@linux-87-01 ~]# zzzz 2>> 1.txt 
[root@linux-87-01 ~]# cat 1.txt 
-bash: hah: command not found
-bash: zzzz: command not found
[root@linux-87-01 ~]#

正确、错误输出都输出到同一个文件。:

#写法1
[root@linux-87-01 ~]# 3333  1>>1.txt 2>>1.txt 
#写法2
[root@linux-87-01 ~]# 3333  1>>1.txt 2>&1
#写法3
[root@linux-87-01 ~]# 3333 &>>1.txt

小结:

重定向符号含义应用场景
>或1>标准输出重定向:先清空文件,然后写入大部分情况下先清空的时候使用
>>或1>>标准输出追加重定向:直接写到文件末尾修改配置文件,表示追加的时候使用
2>标准错误输出重定向:先清空文件,然后写入错误信息较少单独使用
2>>标准错误输出追加重定向:直接把错误信息写到文件末尾较少单独使用
命令>>文件2>&1无论对错,都把结果写入文件比较常用
命令&>>文件无论对错,都把结果写入文件比较常用
<或0<标准输入重定向比较少用
<<或0<<标准输入追加重定向与cat命令搭配使用

输入重定向很少用。

案例:<<与cat使用

[root@linux-87-01 ~]# cat >2.txt<<EOF
> 1
> 2
> 3
> EOF
[root@linux-87-01 ~]# cat 2.txt 
1
2
3
[root@linux-87-01 ~]# 

<<与cat使用格式:

格式1:
cat >文件<<结束标记
格式2:
cat <<EOF >文件

EOF:结束标记,End  Of File
结束标记两边不能有多余符号
1.3 通配符

通配符,常用于Linux中大部分命令

符号含义
*表示所有
{}列出序列,与echo、touch、mkdir使用
[]参考正则中的含义即可
[!]、[^]取反
?任意一个字符

案例:{}使用

[root@linux-87-01 ~]# echo {1..3}
1 2 3
[root@linux-87-01 ~]# echo 1.txt{,.bak}
1.txt 1.txt.bak
[root@linux-87-01 ~]# echo {1..10..2}
1 3 5 7 9

2、正则

正则本质是一些符号:^、$、^$、*等

2.1、正则与通配符的区别
正则匹配文件内容(匹配字符)三剑客、开发语言
区别用途(找的内容不同)支持的命令不同
通配符匹配文件名(命令参数)Linux大部分命令都支持

2.2、正则分类

分类符号
基础正则^ 、$、 ^$、 . 、* 、.*、 [] 、[^]
扩展正则| 、+、 () 、{} 、?

查看文件内容及隐藏的符号:cat -A 文件名

1)基础正则

案例1:查找/etc/passwd文件中以ro开头和以nologin结尾的内容

[root@linux-87-01 ~]# grep '^ro' /etc/passwd
[root@linux-87-01 ~]# grep 'nologin$' /etc/passwd

grep -n:可以显示行号,例如:

[root@linux-87-01 ~]# grep -n '^$' /etc/selinux/config 
1:
13:
14:
[root@linux-87-01 ~]# 

1)^:以什么开头

2)$:以什么结尾

3)^$:过滤空白行

案例2:排除etc/ssh/sshd_config文件中空白行和以#开头的行

[root@linux-87-01 ~]# grep -v '^$' /etc/ssh/sshd_config | grep -v '^#'

4)点(.):表示任意一个字符,不匹配空行

grep -o选项:显示正则匹配到了什么,显示执行过程

5)\:转义字符

6)*:前一个字符连续出现0次或0次以上

[root@linux-87-01 ~]# echo 12345 | grep '5*'
12345
[root@linux-87-01 ~]# echo 12345 | grep -o '5*'
5
[root@linux-87-01 ~]# 

正则的贪婪性:表示连续出现或所有的时候,正则表现出贪婪性,也就是尽可能匹配得多

7).*:所有,任意字符。

.:表示任意一个
*:表示前一个字符连续出现0次或0次以上
.*:表示所有

例如:

[root@linux-87-01 ~]# grep -n '^.*root' /etc/passwd
1:root:x:0:0:root:/root:/bin/bash
10:operator:x:11:0:operator:/root:/sbin/nologin
[root@linux-87-01 ~]# 

8)[]:表示匹配任意1个字符。

比如,[abc]表示匹配a或b或c,即abc中的任意1个

[root@linux-87-01 ~]# echo 12345 | grep '[123]'
12345
[root@linux-87-01 ~]# 

[a-z]:a到z的任意1个

[0-9]:0到9

[a-zA-Z]:a到z的任意1个大小写

[a-Z]:a到z的任意1个大小写

[0-Z]:数字、a到Z

案例1:匹配出/etc/passwd文件中以m或n开头的行

[root@linux-87-01 ~]# grep '^[mn]' /etc/passwd
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
[root@linux-87-01 ~]# 

9)[^]、[^abc]:表示匹配任意1个字符,排除abc,中括号相当于1个字符

小结:

基础正则含义
^以什么开头
$以什么结尾
^$空行
.任意一个字符
\转义字符
*前一个字符出现0次或0次以上
.*所有
[][abc]:a或b或c,[]相当于是1个字符
[^][^abc]:匹配除了abc以外的内容,[]相当于是1个字符
2)扩展正则

egrep或grep -E支持扩展正则

sed使用sed -r支持扩展正则

awk默认支持扩展正则

1)+:前一个字符连续出现1次或1次以上

#3种写法
[root@linux-87-01 ~]# grep -E 'o+' /etc/passwd
[root@linux-87-01 ~]# grep 'o\+' /etc/passwd
[root@linux-87-01 ~]# egrep  'o+' /etc/passwd

[root@linux-87-01 ~]# echo http  https | grep -E 'https+'
http https
[root@linux-87-01 ~]# 

例如:+与[]使用

[root@linux-87-01 ~]# echo 12345 | grep -E '[0-9]+'
12345
[root@linux-87-01 ~]#

2)|:或者

[root@linux-87-01 ~]# echo 12345 | grep -E '2|3'
12345
[root@linux-87-01 ~]# 

3)():表示一个整体,用于后向引用(反向引用sed)

例如:检查系统中tree、vim软件是否安装

[root@linux-87-01 ~]# rpm -qa | grep -E '^(tree|vim)'
vim-common-7.4.629-8.el7_9.x86_64
vim-minimal-7.4.629-7.el7.x86_64
vim-filesystem-7.4.629-8.el7_9.x86_64
vim-enhanced-7.4.629-8.el7_9.x86_64
[root@linux-87-01 ~]# 

4){}:用法:a{n,m}表示a字符连续出现至少n次,最多m次

[root@linux-87-01 ~]# echo 1122223 | grep -E '2{1,2}'
1122223
[root@linux-87-01 ~]# 

a{n}:前一个字符a连续出现n次

a{n,}:前一个字符a连续出现至少n次

a{,m}:前一个字符a连续出现最多m次

身份证号码匹配:

地区: [1-9]\d{5}     \d:表示数字
年的前两位: (18|19|([23]\d))            1800-2399
年的后两位: \d{2}
月份: ((0[1-9])|(10|11|12))
天数: (([0-2][1-9])|10|20|30|31)          闰年不能禁止29+

三位顺序码: \d{3}
两位顺序码: \d{2}

校验码: [0-9Xx]

正则表达式:
十八位: ^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$

十五位: ^[1-9]\d{5}\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{2}$

总:

( ^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$)|(^[1-9]\d{5}\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{2}$)

ip地址匹配:

[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\   #但并不完美,无法精确匹配0-255
0-99  :          ^[0-9]{1,2}$
1开头:100-199    ^1[0-9]{2}$
2开头:200-249    ^2[0-4][0-9]$
2开头:250-255    ^25[0-5]$

grep -Ew:w,精确匹配

5)?:前一个字符出现0次或1次

[root@linux-87-01 ~]# echo http  https | grep -E 'https?'
http https
[root@linux-87-01 ~]#

匹配指定后缀的域名:

^(https?://)?.*(\.com|\.cn|\.com.cn)$

小结:

扩展正则含义
|或者
+前一个字符连续出现1次或多次
()1、表示一个整体,2、用于后向引用(反向引用sed)
{}a{n,m}表示字符a连续出现至少n次,最多m次
?前一个字符出现0次或1次

3、grep

grep的选项:

-v    排除、取反
-n    显示行号
-E    支持正则,grep  -E  等于 egrep
-o    显示过程、显示正则匹配到了什么
-w    精确匹配
-i    过滤的时候不区分大小写
-P    支持perl语言的正则

精确匹配:

[root@linux-87-01 ~]# echo abc  1abcd | grep -w 'abc'
abc 1abcd
[root@linux-87-01 ~]# echo abc  1abcd | grep  '\babc\b'
abc 1abcd
[root@linux-87-01 ~]# echo abc  1abcd | grep  '\<abc\>'
abc 1abcd
[root@linux-87-01 ~]# 

4、sed

4.1 三剑客对比
三剑客通用应用场景
grep、egrep过滤擅长过滤
sed过滤替换,精确过滤(取行)
awk过滤取列,统计与计算
4.2 sed核心功能

增删改查

查(过滤)
改(替换)
删除
增加

案例01:显示/etc/passwd文件的第3行

[root@linux-87-01 ~]# sed -n '3p' /etc/passwd

选项:

-n  :取消默认输出,sed默认情况下会把文件内容都输出。一般在使用p的时候,使用-n
'3p':表示找谁干啥
找谁:条件 找行,3表示第3行
干啥:动作  p(print)显示

案例02:显示/etc/passwd文件的3-5行内容

[root@linux-87-01 ~]# sed -n '3,5p' /etc/passwd

案例03:过滤出/etc/passwd文件以bash结尾的行

#使用grep
[root@linux-87-01 ~]# grep 'bash$' /etc/passwd

#使用sed
[root@linux-87-01 ~]# sed -nr '/bash$/p' /etc/passwd

选项:

-r :表示支持正则
'//p':类似于grep功能

案例04:在日志中过滤,根据时间范围过滤某一天的11:05:00到11:07:00的日志

假设日志文件为:access.log,第4列为时间,格式为:[22/Nov/2015:11:02:00 +0800]

sed -n ‘/从哪里来/,/到哪里去/p’ 文件

sed -n ‘/ /,/ /p’ 文件

[root@linux-87-01 ~]# sed -n '/11:05:00/,/11:07:00/p'  access.log

sed查找功能小结:

类似于grep、egrep过滤
sed可以指定行号,某一个,连续多行内容
sed可以grep、egrep过滤,sed  -n  '//p'  文件名
sed可以过滤范围的内容(比如,日志通过日期范围)

案例01:修改 /etc/selinux/config文件的SELINUX=enforcing为SELINUX=disabled

[root@linux-87-01 ~]# sed 's#SELINUX=enforcing#SELINUX=disabled#g' /etc/selinux/config

执行结果并没有修改文件,必须加上-i选项:

[root@linux-87-01 ~]# sed 's#SELINUX=enforcing#SELINUX=disabled#g' /etc/selinux/config

也可以修改某行:

sed  -i  'ns###g'   文件
其中,
n为第n行,s为substitute(替换),
g为global(全局),也就是全部替换,否则只替换每一行的第1个内容,
#为分隔符,可以自定义,如/、@等等

替换前先备份再修改:

sed  -i.bak  's###g'  文件

选项说明:

-n  取消默认输出,sed默认情况下会把文件内容都输出。一般在使用p的时候,使用-n
-r  支持扩展正则
-i  修改文件内容,替换的时候用。如果有多个选项,要放在所有选项最后
-i.bak  先备份,再修改

一般地,不建议直接-i,先确保正确,才用-i做最后修改。

4.5 删除功能

d:delete,按照行为单位删除(相当于grep -v)

案例01:排除/etc/ssh/sshd_config文件的空行和注释行

# 使用egrep
[root@linux-87-01 ~]# egrep -v '^$|#' /etc/ssh/sshd_config
#使用sed
[root@linux-87-01 ~]# sed -r '/^$|#/d' /etc/ssh/sshd_config 

这里源文件并没有实际删除

4.6 增加功能

如:

[root@linux-87-01 ~]# seq 5 | sed '3a haha'
1
2
3
haha
4
5
[root@linux-87-01 ~]# 
3a haha:表示在第3行下面添加haha内容,haha就为第4行了
3i :则表示第3行上面面添加
3c:则表示把第3行替换

选项解释:

a:append,在指定行下面追加内容
i:insert,在指定行上面追加内容
c:replace,替换指定行内容
4.7 反向引用

一般用于对数据进行加工

需求:比如,要在12345的两边分别加上<>,变成<12345>

[root@linux-87-01 ~]# echo 12345 | sed -r 's#([0-9]+)#<\1>#g'
<12345>
[root@linux-87-01 ~]# 

解释:

([0-9]+):用()分组
\1:表示1组

如果要:12-34-56则:

[root@linux-87-01 ~]# echo 123456 | sed -r 's#(..)(..)(..)#\1-\2-\3#g'
12-34-56
[root@linux-87-01 ~]#

案例1:把/etc/passwd文件复制到/root目录中,然后把该文件的第1列和最后1列调换

[root@linux-87-01 ~]# cp /etc/passwd .

/etc/passwd文件内容格式如下:

root:x:0:0:root:/root:/bin/bash

以:为分隔符,共7列,根据题意,调换1、7列,可以分三组,第1列为第1组,最后1列为第3组,剩下的为第2组。

使用()分组

[root@linux-87-01 ~]# sed -r 's#^(.*)(:x:.*:)(/.*$)#\3\2\1#g' passwd

重点是:怎么写正则,然后分组。

4.8 选项小结
-n  取消默认输出,sed默认情况下会把文件内容都输出。一般在使用p的时候,使用-n
-r  支持扩展正则
-i  修改文件内容,替换的时候用。如果有多个选项,要放在所有选项最后
-i.bak  先备份,再修改

案例:使用sed命令取出ip地址

使用ip a s eth0或ip addr show eth0都可以查看eth0网卡的ip地址

[root@linux-87-01 ~]# ip a s eth0 | sed -n '3p' | sed -r 's#^.*et (.*)/.*$#\1#g'
192.168.10.100
[root@linux-87-01 ~]# 

5、awk

5.1 取列功能

awk默认以空格分隔

案例01:ll /etc/取出第1、5列和最后一列

[root@linux-87-01 ~]# ll /etc/ | awk '{print $1,$5,$NF}

参数:

$NF:最后1列
NF:Number of Fields,每一行多少列
$1:第1列
$5:第5列

案例02:取出/etc/passwd中的第1列、最后1列,倒数第二列

[root@linux-87-01 ~]# awk -F ':' '{print $1,$NF,$(NF-1)}' /etc/passwd

选项:

-F:指定分隔符,只要不是用空格作为分隔符的时候,就使用-F指定。支持正则

案例03:取出ip

#以空格或/为分隔符
#ip a s eth0的结果,inet的前面有4个空格
[root@linux-87-01 ~]# ip a s eth0 | sed -n '3p' | awk -F'[ /]+' '{print $3}'
192.168.10.100
[root@linux-87-01 ~]# ip a s eth0 | awk 'NR==3' | awk -F'inet |/24' '{print $2}'
192.168.10.100

[ /]+的说明:

[  /]:仅会一个一个匹配空格或/,结合-F,就会遇到1个空格或/就会分隔1次
[  /]+:则会匹配连续出现的空格或/,这样多个连续的空格只会被-F分隔1次

选项:

-F;指定分隔符
NR:行号

案例05:取出stat /etc/hosts结果的权限

[root@linux-87-01 ~]# stat /etc/hosts | sed -n '4p' | awk -F'[(/]' '{print $2}'
0644
[root@linux-87-01 ~]# 
5.2 取行功能

·行号:一行、多行

·过滤://

·做比较

案例1:取出/etc/passwd中的指定行

NR:Mumber of Record

#1、取出第1行
[root@linux-87-01 ~]# awk 'NR==1' /etc/passwd
#2、取出3到最后一行
[root@linux-87-01 ~]# awk 'NR>=3' /etc/passwd
#3、取出3到5行
[root@linux-87-01 ~]# awk 'NR>=3 && NR<=5' /etc/passwd

awk比较符号:

==     等于
!=     不等于
>      大于
>=     大于等于
<      小于
<=     小于等于

逻辑符号:

&& :并且
||:或者

案例02:根据某一列内容进程判断并取行

如果/etc/passwd的第三列数字大于999,则显示这一行

[root@linux-87-01 ~]# awk -F':' '$3>999'  /etc/passwd

案例03:显示磁盘已用5%以上的行

[root@linux-87-01 ~]# df -h | awk -F'[ %]+' '$5 >= 5'

案例04:过滤出包含root或sshd的行

#使用awk
[root@linux-87-01 ~]# awk '/root|sshd/' /etc/passwd
#使用grep
[root@linux-87-01 ~]# grep -E 'root|sshd' /etc/passwd

案例05:范围过滤

与sed类似,例如:

#使用awk
[root@linux-87-01 ~]# seq 10 | awk '/3/,/5/'
3
4
5
[root@linux-87-01 ~]# 
#使用sed
[root@linux-87-01 ~]# seq 10 | sed -n '/3/,/5/p'
3
4
5
[root@linux-87-01 ~]# 

案例06:如果/etc/passwd中的第3列是以0或1开头的,则显示出该行

[root@linux-87-01 ~]# awk -F':'  '$3 ~ /^[01]/' /etc/passwd

$数字 ~ /xxx/:某一列包含xxx内容

案例07:过滤出access.log中的第7列以.jpg或.gif结尾的行数

假设access.log文件分隔符为:空格

[root@linux-87-01 ~]# awk '$7 ~  /(.ipg|.gif)$/'  access.log | wc -l
[root@linux-87-01 ~]# awk '$7 ~ /.ipg$|.gif$/'  access.log | wc -l

取行小结:

1、根据行号,如:NR==1,NR>2
2、根据内容,如:/ xxx /
3、某一列包含xxx内容,$3  ~  /xxx/
4、比较某一列大于、小于、等于xxx内容,如:$3>999
5.3 行列组合

比如先取行,再取列。

格式:

awk格式选项找谁{干啥}’文件(参数)
awk格式-F’:’‘NR==1{print $1}’/etc/passwd
‘条件{动作}’ 条件:找哪一行 动作:输出某几列

案例01:取出ip地址

[root@linux-87-01 ~]# ip addr | grep eth0 | awk 'NR==2' | awk -F'[ /]+' '{print $3}'
192.168.10.100
[root@linux-87-01 ~]# ip addr | grep eth0 | awk -F'[ /]+' 'NR==2{print $3}'
192.168.10.100
[root@linux-87-01 ~]#

案例02:取出当前系统swap占用大小

top、free都可以查看swap使用情况

[root@linux-87-01 ~]# free | awk 'NR==3{print $3}'
[root@linux-87-01 ~]# top -bn1 | awk 'NR==5{print $7}'

top选项:

n:更新的次数,完成后将会退出 top
b:批次档模式,搭配 "n" 参数一起使用
-bn1:就是更新1次,然后退出top命令
5.3 统计与计算

案例01:统计系统内存空闲率

可用内存÷总内存

[root@linux-87-01 ~]# free | awk 'NR==2{print $NF/$2*100"%"}'
84.9413%
[root@linux-87-01 ~]#

案例02:统计/etc/services中空行的数量

#1、使用grep
[root@linux-87-01 ~]# grep -E '(^$)'  /etc/services  | wc -l
#2、使用awk
[root@linux-87-01 ~]# awk '/^$/' /etc/services  | wc -l
#3、awk方法2
[root@linux-87-01 ~]# awk '/^$/{i=i+1;print i}' /etc/services
#使用END
[root@linux-87-01 ~]# awk '/^$/{i=i+1}END{print i}' /etc/services

i=i+1可以写成:i++

END{内容},END{}里面的内容会在awk读取完成文件内容后运行

END{}一般用于输出最终的结果

案例03:求出num.txt文件中每一行数字的总和

先创建num.txt文件:

[root@linux-87-01 ~]# seq 10 > num.txt

求和:

[root@linux-87-01 ~]# awk '{i=i+$1} END{print i}' num.txt 
55
[root@linux-87-01 ~]# 

num.txt文件有10行,每行只有1列,所以:i=i+$1

案例04:计算1到100的总和

[root@linux-87-01 ~]# seq 100 | awk '{i=i+$1}END{print i}'
5050
[root@linux-87-01 ~]# 

案例05:统计access.log文件第10列的总和

access.log文件第10列的单位是字节

[root@linux-87-01 ~]# awk '{i=i+$10}END{print i/1024/1024/1024}' access.log 
2.30828
[root@linux-87-01 ~]#

除以三个1024,结果就是GB了