Linux中文本处理工具三剑客之一grep及shell脚本基础

01 正则表达式

REGEXP: Regular Expressions,由一类特殊字符及文本字符所编写的模式,其中有些字符(元字符)不表示字符字面意义,而表示控制或通配的功能,类似于增强版的通配符功能,但与通配符不同,通配符功能是用来处理文件名,而正则表达式是处理文本内容中字符。

正则表达式被很多程序和开发语言所广泛支持:vim, less,grep,sed,awk, nginx,mysql 等

正则表达式分两类:

基本正则表达式:BRE

扩展正则表达式:ERE

正则表达式引擎:

采用不同算法,检查处理正则表达式的软件模块,如:PCRE(Perl Compatible Regular Expressions)

正则表达式的元字符分类:字符匹配、匹配次数、位置锚定、分组

帮助:man 7 regex

1.1 基本正则表达式元字符

1.1.1 字符匹配

. 匹配任意单个字符,可以是一个汉字
[] 匹配指定范围内的任意单个字符,示例:[wang] [0-9] [a-z] [a-zA-Z]
[^] 匹配指定范围外的任意单个字符,示例:[^wang]
[:alnum:] 字母和数字
[:alpha:] 代表任何英文大小写字符,亦即 A-Z, a-z
[:lower:] 小写字母,示例:[[:lower:]],相当于[a-z]
[:upper:] 大写字母
[:blank:] 空白字符(空格和制表符)
[:space:] 水平和垂直的空白字符(比[:blank:]包含的范围广)
[:cntrl:] 不可打印的控制字符(退格、删除、警铃...)
[:digit:] 十进制数字
[:xdigit:]十六进制数字
[:graph:] 可打印的非空白字符
[:print:] 可打印字符
[:punct:] 标点符号

范例:

1).
# .任意单个字符
[root@centos7 data]#echo r马哥t |grep r..t        #成功匹配,因为匹配的是字符,不是字节
r马哥t
[root@centos7 data]#echo r马哥t |grep r.t
[root@centos7 data]#echo google |grep 'g..gle'
google
[root@centos7 data]#echo google |grep 'g.gle'   #匹配失败,是因为.只能代表一个o
[root@centos7 data]#echo rdirt |grep r.t
[root@centos7 data]#echo rdit |grep r..t
rdit

2)[]
# 匹配[]内的任意单个字符
[root@centos7 ~]#ls /etc/ | grep 'rc[.0-6]'
rc0.d
rc1.d
rc2.d
rc3.d
rc4.d
rc5.d
rc6.d
rc.d
rc.local
[root@centos7 ~]#ls /etc/ | grep 'rc[.0-6].'
rc0.d
rc1.d
rc2.d
rc3.d
rc4.d
rc5.d
rc6.d
rc.d
rc.local
[root@centos7 data]#echo rc. |grep 'rc[.0-6]'
rc.
[root@centos7 data]#echo rc. |grep 'rc[.0-6].'
这个为什么匹配不上,是因为rc.匹配到[]后,后面还有一个.
这个.必须是任意一个字符,不能为空。

3)\
# \转义
[root@centos7 ~]#ls /etc/ | grep 'rc[.0-6]\.'       ##rc后面跟.或0-6数字,再紧跟.的
rc0.d
rc1.d
rc2.d
rc3.d
rc4.d
rc5.d
rc6.d
[.0-6]表示的是.或0123456,而不是说.代表任意一个字符
echo rcx.local |grep 'rc[.0-6]'     #匹配失败

##\转义后,后面只是个“.”;不代表任何其他字符。
[root@centos7 data]#echo rc. |grep 'rc[.0-6]\.' 
[root@centos7 data]#echo rc.d |grep 'rc[.0-6]\.'
[root@centos7 data]#echo rc.. |grep 'rc[.0-6]\.'
rc..
[root@centos7 data]#echo rc.d |grep 'rc[.0-6]'
rc.d
[root@centos7 data]#echo rc.d |grep 'rc[.0-6].'
rc.d

1.1.2 匹配次数

用在要指定次数的字符后面,用于指定前面的字符要出现的次数

*           #匹配前面的字符任意次,可以是0次,一种贪婪模式,尽可能长的匹配
.*          #任意长度的任意字符
\?          #匹配前面的字符0次或1次,即可有可无
\+          #匹配前面的字符至少1次,即肯定有>=1
\{n\}       #匹配前面的字符n次
\{m,n\}     #匹配前面的字符至少m次,至多n次(>m <n)
\{,n\}      #匹配前面的字符至多n次(<=n)
\{n,\}      #匹配前面的字符至少n次(>=n)

范例:

1)*和.*
## *匹配前面的字符任意次,包括0次,贪婪模式:尽可能长的匹配
## .* 任意长度的任意字符
[root@centos7 data]#echo godgle |grep 'g*gle'   #匹配的是gle或多个g后跟gle
godgle
[root@centos7 data]#echo godgle |grep 'go*gle'  #匹配的是ggle或g多个o后跟gle,而go和gle中间还有字母d,所以匹配不上
[root@centos7 data]#echo gogle |grep 'go*gle'
gogle
[root@centos7 data]#echo gooooooogle |grep 'go*gle'
gooooooogle
[root@centos7 data]#echo gooorfeoooogle |grep 'go*gle'
[root@centos7 data]#echo gooorfeoooogle |grep 'go.*gle' #.*任意长度任意字符
gooorfeoooogle
[root@centos7 data]#echo ggle |grep 'g.*gle'
ggle

3)\? 
## \?匹配其前面的字符0或1次,即:可有可无
[root@centos7 data]#echo ggle |grep 'g\?gle'    ##匹配的是gle或ggle
ggle
[root@centos7 data]#echo gle |grep 'g\?gle'     ##匹配的是gle
gle
[root@centos7 data]#echo gogle |grep 'g\?gle'   ##匹配的是gle
gogle
[root@centos7 data]#echo gosdfgle |grep 'g\?gle'    ##也是gle
gosdfgle
[root@centos7 data]# echo fogle |grep 'g\?gle'
fogle
[root@centos7 data]# echo fogle |grep 'h\?gle'
fogle
[root@centos7 data]#echo google |grep 'go\?gle'     #匹配的是ggle或gogle
#匹配失败,是因为要匹配“o”0次或1次,但google有两个o

[root@centos7 data]# echo dgogle |grep 'go\?gle'
dgogle
[root@centos7 data]# echo dgfogle |grep 'go\?gle'
[root@centos7 data]# echo dgogle |grep 'gom\?gle'       ##匹配的是gomgle或gogle
dgogle
[root@centos7 data]# echo dgomgle |grep 'gom\?gle'
dgomgle
[root@centos7 data]# echo dgmogle |grep 'gom\?gle'
[root@centos7 data]# echo gomggle |grep 'gom\?gle'
[root@centos7 data]# echo gomdsfgogle |grep 'gom\?gle'
gomdsfgogle

[root@centos7 data]# echo /etc/ |grep '/etc/\?'
/etc/
[root@centos7 data]# echo /etc |grep '/etc/\?'
/etc

4)\+
\+ 匹配其前面的字符至少1次,即:肯定有,>=1
[root@centos7 data]# echo goooooooooogle |grep 'go\+gle'
goooooooooogle
[root@centos7 data]# echo gogle |grep 'go\+gle'
gogle
[root@centos7 data]# echo ggle |grep 'go\+gle'      #o至少匹配一次

[root@centos7 data]# echo /etc |grep "/etc/\+"
[root@centos7 data]# echo /etc/ |grep "/etc/\+"
/etc/

5)
\{n\} 匹配前面的字符n次
\{m,n\} 匹配前面的字符至少m次,至多n次
\{,n\} 匹配前面的字符至多n次,<=n
\{n,\} 匹配前面的字符至少n次

[root@centos7 data]# echo goooooogle |grep 'go\{10\}gle'
[root@centos7 data]# echo goooooooooogle |grep "go\{10\}gle"
goooooooooogle
[root@centos7 data]# echo goooooooooogle |grep 'go\{3,6\}gle'
[root@centos7 data]# echo google |grep 'go\{3,6\}gle'
[root@centos7 data]# echo google |grep 'go\{2,6\}gle'
google
[root@centos7 data]# echo gooogle |grep 'go\{2,6\}gle'
gooogle
[root@centos7 data]# echo gooogle |grep 'go\{,6\}gle'
gooogle
[root@centos7 data]# echo gooogle |grep 'go\{2,\}gle'
gooogle
[root@centos7 data]# echo gogle |grep 'go\{2,\}gle'
[root@centos7 data]#

1.1.3 位置锚定

位置锚定可以用于定位出现的位置

^           #行首锚定,用于模式的最左侧
$           #行尾锚定,用于模式的最右侧
^PATTERN$   #用于模式匹配整行
^$          #空行
^[[:space:]]*$  #空白行
\< 或 \b         #词首锚定,用于单词模式的左侧
\> 或 \b         #词尾锚定,用于单词模式的右侧
\<PATTERN\>     #匹配整个单词。字母数字下划线组合的都是单词,其他任何符号都是分隔符

1、范例:^和$

[root@centos7 data]# grep root /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
[root@centos7 data]# grep ^root /etc/passwd
root:x:0:0:root:/root:/bin/bash
[root@centos7 data]# grep /bin/bash$ /etc/passwd
root:x:0:0:root:/root:/bin/bash
dong:x:1000:1000::/home/dong:/bin/bash
wang:x:1001:1001::/home/wang:/bin/bash
mage:x:1002:1005::/home/mage:/bin/bash

[root@centos7 data]#  grep ^[wang] /etc/passwd
adm:x:3:4:adm:/var/adm:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
nobody:x:65534:65534:Kernel Overflow User:/:/sbin/nologin
wang:x:1001:1001::/home/wang:/bin/bash
[root@centos7 data]# grep '^#' /etc/fstab
#
# /etc/fstab
# Created by anaconda on Sun Nov 15 18:21:16 2020
#
# Accessible filesystems, by reference, are maintained under '/dev/disk/'.
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info.
#
# After editing this file, run 'systemctl daemon-reload' to update systemd
# units generated from this file.
#
[root@centos7 data]# grep ^'^#' /etc/fstab
[root@centos7 data]# grep ^'#' /etc/fstab
#
# /etc/fstab
# Created by anaconda on Sun Nov 15 18:21:16 2020
#
# Accessible filesystems, by reference, are maintained under '/dev/disk/'.
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info.
#
# After editing this file, run 'systemctl daemon-reload' to update systemd
# units generated from this file.
#
[root@centos7 data]# grep ^UUID /etc/fstab      ##只筛选uuid开头的行
UUID=52d045ca-17ce-4539-b44a-17d8699b1b19 /           xfs     defaults        0 0
UUID=7c4ebe9a-6c26-4f0c-bd98-f06ab3d84039 /boot       ext4    defaults        1 2
UUID=853161e5-66ee-49cb-93ab-846f26397517 /data       xfs     defaults        0 0
UUID=5686d473-7838-4f08-933f-86c72ca51b8a swap        swap    defaults        0 0
[root@centos7 data]# grep -v '^#' /etc/fstab    ##中间用空行的也会显示出来

UUID=52d045ca-17ce-4539-b44a-17d8699b1b19 /           xfs     defaults        0 0
UUID=7c4ebe9a-6c26-4f0c-bd98-f06ab3d84039 /boot       ext4    defaults        1 2
UUID=853161e5-66ee-49cb-93ab-846f26397517 /data       xfs     defaults        0 0
UUID=5686d473-7838-4f08-933f-86c72ca51b8a swap        swap    defaults        0 0
[root@centos7 data]#

2、范例:\< \>

[root@centos7 data]# echo root |grep '\<root'
root
[root@centos7 data]# echo root |grep "\<root"
root
[root@centos7 data]# echo root |grep \<root
[root@centos7 data]# echo -root |grep '\<root'
-root
[root@centos7 data]# echo _root |grep '\<root'
[root@centos7 data]# echo 12root |grep '\<root'
[root@centos7 data]# echo root454r |grep '\<root'
root454r
#注意:字母数字下划线是正常字符,而其他字符如“-:”等都不是,所以-root就能筛选出来,而_root不能。
#下同
[root@centos7 data]# echo ro454root |grep 'root\>'
ro454root
[root@centos7 data]# echo ro454rootr |grep 'root\>'
[root@centos7 data]# echo ro454root: |grep 'root\>'
ro454root:
[root@centos7 data]# echo ro454root- |grep 'root\>'
ro454root-
[root@centos7 data]# echo ro454root_ |grep 'root\>'
[root@centos7 data]# echo ro454root23 |grep 'root\>'
[root@centos7 data]#
#解释同上
[root@centos7 data]# echo dkfrootlsf |grep '\<root\>'
[root@centos7 data]# echo 23root_ |grep '\<root\>'
[root@centos7 data]# echo _root: |grep '\<root\>'
[root@centos7 data]# echo -root: |grep '\<root\>'
-root:
[root@centos7 data]# echo -root* |grep '\<root\>'
-root*
[root@centos7 data]# echo -root# |grep '\<root\>'
-root#
[root@centos7 data]# echo -root@ |grep '\<root\>'
-root@
[root@centos7 data]# echo -root% |grep '\<root\>'
-root%
[root@centos7 data]# echo -root^ |grep '\<root\>'
-root^
[root@centos7 data]# echo -root~ |grep '\<root\>'
-root~
[root@centos7 data]# echo -root& |grep '\<root\>'
-bash: syntax error near unexpected token `|'

实例:提取出df的磁盘利用率

[root@centos7 ~]# df
Filesystem              1K-blocks    Used Available Use% Mounted on
devtmpfs                   486080       0    486080   0% /dev
tmpfs                      497840       0    497840   0% /dev/shm
tmpfs                      497840    7860    489980   2% /run
tmpfs                      497840       0    497840   0% /sys/fs/cgroup
/dev/mapper/centos-root  17811456 2478484  15332972  14% /
/dev/sda1                 1038336  228272    810064  22% /boot
tmpfs                       99572       0     99572   0% /run/user/0

[root@centos7 ~]# df |grep  -o '[0-9]\{1,3\}%'
0%
0%
2%
0%
14%
22%
0%
[root@centos7 ~]# df|grep ^'/dev/sd' |grep -o '[0-9]\{1,3\}%'
22%

1.1.4 分组其它

1.1.4.1 分组

分组:() 将多个字符捆绑在一起,当作一个整体处理,如:\(root\)+
后向引用:分组括号中的模式匹配到的内容会被正则表达式引擎记录于内部的变量中,这些变量的命名
方式为: \1, \2, \3, ...
\1 表示从左侧起第一个左括号以及与之匹配右括号之间的模式所匹配到的字符
示例:

\(string1\(string2\)\)
\1: string1\(string2\)
\2: string2

注意: 后向引用引用前面的分组括号中的模式所匹配字符,而非模式本身

[root@centos7 data]# cat /data/fstab
#
# /etc/fstab
# Created by anaconda on Sun Nov 15 18:21:16 2020
#
# Accessible filesystems, by reference, are maintained under '/dev/disk/'.
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info.
#
# After editing this file, run 'systemctl daemon-reload' to update systemd
# units generated from this file.
#
UUID=52d045ca-17ce-4539-b44a-17d8699b1b19 /             xfs     defaults        0 0
UUID=7c4ebe9a-6c26-4f0c-bd98-f06ab3d84039 /bo           ext4    defaults        1 2
UUID=853161e5-66ee-49cb-93ab-846f26397517 /data         xfs     defaults        0 0
UUID=5686d473-7838-4f08-933f-86c72ca51b8a swap          swap    defaults        0 0

1)要将fstab中#去掉
在vim /data/fstab编辑如下
%s/^#\(.*\)/\1/     ##查找以#开头的行,把#后面的字符当作一个分组,然后用这个分组去替换“#+分组”,就去掉#号了
也可以简化
%s/^#// ##查找#开头的行,把#替换成空

2)要把UUID的行加上#
%s/^UUID/#UUID/
%s/^\(UUID\)/#\1/   ##这是把UUID整体当作一个分组

1.1.4.2 或者

或者:\|

示例:

a\|b #a或b
C\|cat #C或cat
\(C\|c\)at #Cat或cat

范例:排除空行和#开头的行

[root@centos7 data]# grep ^# /etc/fstab
#
# /etc/fstab
# Created by anaconda on Sat Jul  6 14:34:58 2019
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
[root@centos7 data]# grep -v '^#' /etc/fstab    ##还有一个空行

/dev/mapper/centos-root /                         xfs     defaults        0 0
UUID=4d6ce1ba-16ec-4d37-951c-afd012231267 /boot   xfs     defaults        0 0
/dev/mapper/centos-swap swap                      swap    defaults        0 0
[root@centos7 data]# grep -v '^#' /etc/fstab |grep -v ^$
/dev/mapper/centos-root /                         xfs     defaults        0 0
UUID=4d6ce1ba-16ec-4d37-951c-afd012231267 /boot   xfs     defaults        0 0
/dev/mapper/centos-swap swap                      swap    defaults        0 0
[root@centos7 data]# grep -v '^#\|^$' /etc/fstab        ##同上
[root@centos7 data]# grep -v '^\(#\|$\)' /etc/fstab     ##同上
[root@centos7 data]# grep "^[^#]" /etc/fstab
/dev/mapper/centos-root /                         xfs     defaults        0 0
UUID=4d6ce1ba-16ec-4d37-951c-afd012231267 /boot   xfs     defaults        0 0
/dev/mapper/centos-swap swap                      swap    defaults        0 0

实例:

统计network文件去掉#和空行后,共有多少行
[root@centos7 data]# cat /etc/init.d/network|wc -l
264
[root@centos7 data]# grep -v '^#' /etc/init.d/network|grep -v '^$'|wc -l
199
[root@centos7 data]# grep -v '^#\|^$' /etc/init.d/network|wc -l
199
[root@centos7 data]# grep -v '^\(#\|$\)' /etc/init.d/network|wc -l
199
[root@centos7 data]# grep "^[^#]" /etc/init.d/network|wc -l
199
[root@centos7 data]# grep "^[^#$]" /etc/init.d/network|wc -l
199
^[^#$]  把#行和空行都排除,而^[^#]也可以。
^[^#]表示行首不能是#的一个字符,而空行不是字符。括号内表示非#,空行也是非#,但不是一个字符,所以包含在内。

1.1.5 基本正则表达式练习

1、显示/proc/meminfo文件中以大小s开头的行(要求:使用两种方法)
[root@centos7 data]# grep ^'\(S\|s\)' /proc/meminfo
SwapCached:            0 kB
SwapTotal:       2097148 kB
SwapFree:        2097148 kB
Shmem:              7828 kB
Slab:              44728 kB
SReclaimable:      20800 kB
SUnreclaim:        23928 kB
[root@centos7 data]# grep -e ^S -e ^s /proc/meminfo
SwapCached:            0 kB
SwapTotal:       2097148 kB
SwapFree:        2097148 kB
Shmem:              7828 kB
Slab:              44728 kB
SReclaimable:      20800 kB
SUnreclaim:        23928 kB

2、显示/etc/passwd文件中不以/bin/bash结尾的行
[root@centos7 data]# grep -v '/bin/bash$' /etc/passwd
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
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
polkitd:x:999:998:User for polkitd:/:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
chrony:x:998:996::/var/lib/chrony:/sbin/nologin

3、显示用户wang默认的shell程序
[root@centos7 data]# grep ^wang /etc/passwd|cut -d: -f7
/bin/bash

4、找出/etc/passwd中的两位或三位数
[root@centos7 data]# grep -v '[0-9]\{4,\}' /etc/passwd|grep '[0-9]\{2,3\}'
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
polkitd:x:999:998:User for polkitd:/:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
chrony:x:998:996::/var/lib/chrony:/sbin/nologin

5、显示CentOS7的/etc/grub2.cfg文件中,至少以一个空白字符开头的且后面有非空白字符的行
[root@centos7 data]# grep '^[[:blank:]]\+[[:graph:]]' /etc/grub2.cfg
...省略...

6、找出“netstat -tan”命令结果中以LISTEN后跟任意多个空白字符结尾的行
[root@centos7 data]# netstat -tan|grep 'LISTEN[[:blank:]].*'
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN
tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN
tcp6       0      0 :::22                   :::*                    LISTEN
tcp6       0      0 ::1:25                  :::*                    LISTEN
[root@centos7 data]# netstat -tan|grep 'LISTEN[[:blank:]].*$'
[root@centos7 data]# netstat -tan|grep 'LISTEN[[:space:]]*$'
[root@centos7 data]# netstat -tan|grep '\<LISTEN*\>'

7、显示CentOS7上所有UID小于1000以内的用户名和UID
[root@centos7 data]# grep -v '[0-9]\{4,\}' /etc/passwd|cut -d: -f1,3
root:0
bin:1
daemon:2
adm:3
lp:4
sync:5
shutdown:6
halt:7
mail:8
operator:11
games:12
ftp:14
nobody:99
systemd-network:192
dbus:81
polkitd:999
sshd:74
postfix:89
chrony:998

1.2 扩展正则表达式

1.2.1 字符匹配元字符

.           #任意单个字符
[wang]      #指定范围的字符
[^wang]     #不在指定范围的字符
[:alnum:]   #字母和数字
[:alpha:]   #代表任何英文大小写字符,亦即 A-Z, a-z
[:lower:]   #小写字母,示例:[[:lower:]],相当于[a-z]
[:upper:]   #大写字母
[:blank:]   #空白字符(空格和制表符)
[:space:]   #水平和垂直的空白字符(比[:blank:]包含的范围广)
[:cntrl:]   #不可打印的控制字符(退格、删除、警铃...)
[:digit:]   #十进制数字
[:xdigit:]  #十六进制数字
[:graph:]   #可打印的非空白字符
[:print:]   #可打印字符
[:punct:]   #标点符号

1.2.2 匹配次数

*       #匹配前面字符任意次,>=0
?       #0或1次
+       #1次或多次,>=1
{n}     #匹配n次
{m,n}   #至少m,至多n次,>=m,<=n
{n,}    #至少n次,>=n
{,n}    #至多n次,<=n

1.2.3 位置锚定

^       #行首
$       #行尾
\<, \b  #语首
\>, \b  #语尾
<pattern>
^pattern$

1.2.4 分组和其他

()      #分组,后向引用:\1, \2, ...
|       #或者
a|b     #a或b
C|cat   #C或cat
(C|c)at #Cat或cat

1.2.5 练习

1、显示三个用户root、mage、wang的UID和默认shell
[root@centos7 data]# grep  '^\(root\|mage\|wang\)' /etc/passwd
root:x:0:0:root:/root:/bin/bash
wang:x:1013:1013::/home/wang:/bin/bash
mage:x:1014:1014::/home/mage:/bin/bash
mageia:x:1100:1100::/home/linux:/bin/bash       ##mageia用户包含了mage字符,也能匹配上
[root@centos7 data]# grep ^'\(root\>\|mage\>\|wang\>\)' /etc/passwd  ##加上\>,定位语尾
root:x:0:0:root:/root:/bin/bash
wang:x:1013:1013::/home/wang:/bin/bash
mage:x:1014:1014::/home/mage:/bin/bash
[root@centos7 data]# grep -E '^(root|mage|wang)\>' /etc/passwd      ##加上\>,定位词尾
root:x:0:0:root:/root:/bin/bash
wang:x:1013:1013::/home/wang:/bin/bash
mage:x:1014:1014::/home/mage:/bin/bash

2、找出/etc/rc.d/init.d/functions文件中行首为某单词(包括下划线)后面跟一个小括号的行
[root@centos7 data]# grep -E ^'[[:alpha:]]|_' /etc/rc.d/init.d/functions |grep '()'
systemctl_redirect () {     ###这行字母和()直接有个空格
checkpid() {
__kill_pids_term_kill_checkpids() {
__kill_pids_term_kill() {
__pids_var_run() {
__pids_pidof() {
daemon() {
killproc() {
pidfileofproc() {
pidofproc() {
status() {
echo_success() {
echo_failure() {
echo_passed() {
echo_warning() {
update_boot_stage() {
success() {
failure() {
passed() {
warning() {
action() {
strstr() {
is_ignored_file() {
convert2sec() {         ##这行有数字
is_true() {
is_false() {
apply_sysctl() {
[root@centos7 data]# grep -E '^[[:alpha:]_]+\(\)' /etc/rc.d/init.d/functions
checkpid() {
__kill_pids_term_kill_checkpids() {
__kill_pids_term_kill() {
__pids_var_run() {
__pids_pidof() {
daemon() {
killproc() {
pidfileofproc() {
pidofproc() {
status() {
echo_success() {
echo_failure() {
echo_passed() {
echo_warning() {
update_boot_stage() {
success() {
failure() {
passed() {
warning() {
action() {
strstr() {
is_ignored_file() {
is_true() {
is_false() {
apply_sysctl() {
##再改进,加上包含数字和空格,就能匹配到下面的两行
[root@centos7 data]# grep -E '^[[:alnum:]_]+ ?\(\)' /etc/rc.d/init.d/functions
...以上内容,省略...
systemctl_redirect () {
convert2sec() {

3、使用egrep取出/etc/rc.d/init.d/functions中其基名
[root@centos7 data]# echo /etc/rc.d/init.d/functions |egrep -o '[^/]+/?$'
functions
[root@centos7 data]# echo /etc/rc.d/init.d/functions |egrep -o '[^/]+'|tail -1
functions

4、使用egrep取出上面路径的目录名
[root@centos7 data]# echo /etc/rc.d/init.d/functions |egrep -o '/.*/'
/etc/rc.d/init.d/

5、统计last命令中以root登录的每个主机IP地址登录次数
[root@centos7 data]# last|grep ^root|tr -s ' ' :|cut -d: -f3|sort|uniq -c
     40 192.168.100.1
      4 192.168.100.180
      1 192.168.100.200

6、利用扩展正则表达式分别表示0-9、10-99、100-199、200-249、250-255
0-9:[0-9]
10-99:[1-9][0-9]
100-199:1[0-9][0-9]
200-249:2[0-4][0-9]
250-255:25[0-5]

7、显示ifconfig命令结果中所有IPv4地址
[root@centos7 data]# ifconfig|grep -E -o '([0-9]{1,3}\.){3}[0-9]{1,3}'
192.168.100.11
255.255.255.0
192.168.100.255
172.16.100.11
255.255.255.0
172.16.100.255
127.0.0.1
255.0.0.0
[root@centos7 data]# ifconfig|grep 'inet '|tr -s ' '|cut -d' ' -f3
192.168.100.11
172.16.100.11
127.0.0.1

8、将此字符串:welcome to magedu linux 中的每个字符去重并排序,重复次数多的排到前面
[root@centos7 data]# echo "welcome to magedu linux" |egrep -o '[[:alpha:]]'|sort|uniq -c|sort -nr
      3 e
      2 u
      2 o
      2 m
      2 l
      1 x
      1 w
      1 t
      1 n
      1 i
      1 g
      1 d
      1 c
      1 a

02 文本处理三剑客

grep:主要对文本的(正则表达式)行基于模式进行过滤

sed:stream editor,文本编辑工具

awk:Linux上的实现gawk,文本报告生成器

2.1 文本处理三剑客之 grep

grep:Global search REgular expression and Print out the line

作用:文本搜索工具,根据用户指定的“模式”对目标文本逐行进行匹配检查;打印匹配到的行

模式:由正则表达式字符及文本字符所编写的过滤条件

格式:

grep [OPTIONS] PATTERN [FILE...]

2.1.1 常见选项

--color=auto    #对匹配到的文本着色显示
-m #    #匹配#次后停止
-v      #显示不被pattern匹配到的行
-i      #忽略字符大小写
-n      #显示匹配的行号
-c      #统计匹配的行数
-o      #仅显示匹配到的字符串
-q      #静默模式,不输出任何信息
        #例:grep -q root /etc/passwd
        #    echo $?    #查看是否有包含root的行,0为真,非0为假
-A #    #after, 后#行
-B #    #before, 前#行
-C #    #context, 前后各#行
-e      #实现多个选项间的逻辑or关系,如:grep –e 'cat' -e 'dog' file
        #或关系grep -e root -e bash /etc/passwd
        #与关系grep root /etc/passwd |grep bash
-w      #匹配整个单词
-E      #使用ERE,相当于egrep
-F      #不支持正则表达式,相当于fgrep
-f      #file 根据模式文件处理
-r      #递归目录,但不处理软链接
-R      #递归目录,但处理软链接

2.1.2 常用选项范例

1)-o
[root@centos7 data]#grep -o 'r..t' /etc/passwd
root
root
root
root
r/ft
rypt

2)-f
##查看passwd文件中匹配f1文件的关键词的行。
[root@centos7 data]#cat f1.txt
root
bash
[root@centos7 data]#grep -f f1.txt /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
wang:x:1000:1000::/home/wang:/bin/bash
mage:x:1001:1001::/home/mage:/bin/bash
#以上操作类似于grep -e root -e bash /etc/passwd

##取两个文件的相同行
[root@centos7 data]#cat f1.txt
a
b
1
c
[root@centos7 data]#cat f2.txt
b
e
f
c
1
2
[root@centos7 data]#grep -f f2.txt f1.txt   ##从f1中选出包含在f2文件中的行
b
c
1
#相当于cat f1.txt f2.txt | sort |uniq -d #合并两个文件排序取相同行

3)-v
#基本正则表达式
[root@centos7 data]#grep -v "^#" /etc/profile | grep -v '^$'
[root@centos7 data]#grep -v "^#\|^$" /etc/profile
[root@centos7 data]#grep -v "^\(#\|$\)" /etc/profile
#扩展正则表达式
[root@centos7 data]#grep -Ev "^(#|$)" /etc/profile
[root@centos7 data]#egrep -v "^(#|$)" /etc/profile

##查询/etc/passwd包含root和bash的行
[root@centos7 data]# grep 'root\|bash' /etc/passwd
[root@centos7 data]# grep -e 'root' -e 'bash' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
oldboy:x:1000:1000::/home/oldboy:/bin/bash
dong:x:1001:1001::/home/dong:/bin/bash
wang:x:1013:1013::/home/wang:/bin/bash
mage:x:1014:1014::/home/mage:/bin/bash
mandriva:x:1005:2019::/home/mandriva:/bin/bash
[root@centos7 data]# grep -E 'root|bash' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
oldboy:x:1000:1000::/home/oldboy:/bin/bash
dong:x:1001:1001::/home/dong:/bin/bash
wang:x:1013:1013::/home/wang:/bin/bash
mage:x:1014:1014::/home/mage:/bin/bash
mandriva:x:1005:2019::/home/mandriva:/bin/bash

实例:

1)取本机磁盘利用率最高值
[root@centos7 ~]# df|grep ^'/dev/sd'|tr -s ' ' %|cut -d% -f5|sort -nr|head -1
22

2)查看并发连接最多的远程主机IP
[root@centos7 ~]# ss -nt|tail -n +2|tr -s ' ' :|cut -d: -f6|sort|uniq -c|sort -nr
      4 192.168.100.1
      1 192.168.100.200
      1 192.168.100.180
[root@centos7 ~]# ss -nt |grep ESTAB|tr -s ' ' :|cut -d: -f6|sort|uniq -c|sort -nr
      4 192.168.100.1
      1 192.168.100.200
      1 192.168.100.180

3)查看本机IPv4地址
[root@centos7 ~]# ifconfig|grep -E '[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}'
        inet 192.168.100.11  netmask 255.255.255.0  broadcast 192.168.100.255
        inet 172.16.100.11  netmask 255.255.255.0  broadcast 172.16.100.255
        inet 127.0.0.1  netmask 255.0.0.0
[root@centos7 ~]#ifconfig |grep -E '([0-9]{1,3}.){3}[0-9]{1,3}'
        inet 192.168.100.11  netmask 255.255.255.0  broadcast 192.168.100.255
        inet 172.16.100.11  netmask 255.255.255.0  broadcast 172.16.100.255
        inet 127.0.0.1  netmask 255.0.0.0
[root@centos7 ~]# ifconfig ens33|grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}'
192.168.100.11
255.255.255.0
192.168.100.255
[root@centos7 ~]#ifconfig ens33|grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}'|head -1
192.168.100.11
[root@centos7 ~]#cat regex.txt
([0-9]{1,3}\.){3}[0-9]{1,3}
[root@centos7 data]#ifconfig ens33|grep -oEf regex.txt
192.168.100.11

4)添加用户bash、testbash、basher、sh、nologin(其shell为/sbin/nologin),找出/etc/passwd用户
名和shell同名的行
#初始化文件
useradd bash
useradd testbash
useradd basher
useradd sh
useradd -s /sbin/nologin nologin
#以上是单独添加用户,若批量添加用户,需要使用sh脚本

#新建一个简单的uadd.sh的脚本
[root@centos7 data]# vi uadd.sh
#!/bin/bash
useradd nologin -s /sbin/nologin
for username in bash testbash basher sh
do
    useradd $username
done
[root@centos7 data]# chmod +x uadd.sh       ##添加可执行权限
[root@centos7 data]# sh uadd.sh             ##执行脚本添加用户
[root@centos7 data]# cat /etc/passwd        ##查看新建的用户
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
...省略...
nologin:x:2006:2006::/home/nologin:/sbin/nologin
bash:x:2007:2007::/home/bash:/bin/bash
testbash:x:2008:2008::/home/testbash:/bin/bash
basher:x:2009:2009::/home/basher:/bin/bash
sh:x:2010:2010::/home/sh:/bin/bash

##测试,找出/etc/passwd用户名和shell同名的行
[root@centos7 data]# grep '^\(.*\)\>.*\<\1$' /etc/passwd
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
nologin:x:2006:2006::/home/nologin:/sbin/nologin
bash:x:2007:2007::/home/bash:/bin/bash
[root@centos7 data]# grep -E '^(.*)\>.*\<\1$' /etc/passwd
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
nologin:x:2006:2006::/home/nologin:/sbin/nologin
bash:x:2007:2007::/home/bash:/bin/bash

2.1.3 练习

1、统计出/etc/passwd文件中其默认shell为非/sbin/nologin的用户个数,并将用户都显示出来

用户个数:
[root@centos7 ~]# grep -v '/sbin/nologin$' /etc/passwd|cut -d: -f1 |wc -l
17
用户:
[root@centos7 ~]# grep -v '/sbin/nologin$' /etc/passwd|cut -d: -f1
root
sync
shutdown
halt
oldboy
dong
wang
mage
mandriva
mageia
user1
user2
user3
bash
testbash
basher
sh

2、查出用户UID最大值的用户名、UID及shell类型

[root@centos7 ~]# cat /etc/passwd|sort -nrt: -k3
sh:x:2010:2010::/home/sh:/bin/bash
basher:x:2009:2009::/home/basher:/bin/bash
testbash:x:2008:2008::/home/testbash:/bin/bash
bash:x:2007:2007::/home/bash:/bin/bash
nologin:x:2006:2006::/home/nologin:/sbin/nologin
user3:x:2005:2005::/home/user3:/bin/bash
user2:x:2004:2004::/home/user2:/bin/bash
user1:x:2003:2003::/home/user1:/bin/bash
slackware:x:2002:2019::/home/slackware:/sbin/nologin
mageia:x:1100:1100::/home/linux:/bin/bash
mage:x:1014:1014::/home/mage:/bin/bash
wang:x:1013:1013::/home/wang:/bin/bash
...省略...

[root@centos7 ~]# cat /etc/passwd|sort -nrt: -k3|head -1|cut -d: -f1,3,7
sh:2010:/bin/bash

3、统计当前连接本机的每个远程主机IP的连接数,并按从大到小排序

[root@centos7 ~]# ss -nt |grep ESTAB|tr -s ' ' :|cut -d: -f6|sort|uniq -c|sort -nr
      4 192.168.100.1
      1 192.168.100.200
      1 192.168.100.180

03 shell 脚本语言的基本用法

3.1 shell 脚本的用途

  • 自动化常用命令
  • 执行系统管理和故障排除
  • 创建简单的应用程序
  • 处理文本或文件

3.2 shell 脚本基本结构

shell脚本编程:是基于过程式、解释执行的语言

编程语言的基本结构:

  • 各种系统命令的组合
  • 数据存储:变量、数组
  • 表达式:a + b
  • 控制语句:if

shell脚本:包含一些命令或声明,并符合一定格式的文本文件

格式要求:首行shebang机制

#!/bin/bash
#!/usr/bin/python
#!/usr/bin/perl

3.3 shell脚本创建过程

第一步:使用文本编辑器来创建文本文件

第一行必须包括shell声明序列:#!

示例:添加注释,注释以#开头

#!/bin/bash

第二步:加执行权限

给予执行权限,在命令行上指定脚本的绝对或相对路径

chmod +x filename.sh

第三步:运行脚本

直接运行解释器,将脚本作为解释器程序的参数运行

. /data/filename.sh
source /data/filename.sh
sh /data/filename.sh
/bin/bash /data/filename.sh

#直接执行文件名filename.sh,前提是把当前目录.加到PATH路径中。
#如果把当前路径加到PATH变量中,就可以在当前路径执行sh脚本时,不用前面加./了。
vi /etc/profile.d/env.sh
PATH=".:$PATH"
#保存退出后,执行. /etc/profile.d/env.sh生效,即可。
#生成环境中还是要慎用。

3.4 shell 脚本注释规范

  1. 第一行一般为调用使用的语言
  2. 程序名,避免更改文件名为无法找到正确的文件
  3. 版本号
  4. 更改后的时间
  5. 作者相关信息
  6. 该程序的作用,及注意事项
  7. 最后是各版本的更新简要说明
##shell脚本注释规范
[root@centos7 ~]# vim .vimrc
  1 set nu
  2 set ignorecase
  3 set cursorline
  4 set autoindent
  5 autocmd BufNewFile *.sh exec ":call SetTitle()"
  6 func SetTitle()
  7         if expand("%:e") == 'sh'
  8         call setline(1,"#!/bin/bash")
  9         call setline(2,"#")
 10         call setline(3,"#***************************************")
 11         call setline(4,"#Author:        dong")
 12         call setline(5,"#QQ:            25448779")
 13         call setline(6,"#Date:          ".strftime("%Y-%m-%d"))
 14         call setline(7,"#FileName:      ".expand("%"))
 15         call setline(8,"#URL:           http://www.magedu.com")
 16         call setline(9,"#Description:   The test script")
 17         call setline(10,"#Copyright (C):        ".strftime("%Y")." All rights reserved")
 18         call setline(11,"#***************************************")
 19         call setline(12,"")
 20         endif
 21 endfunc
 22 autocmd BufNewFile * normal G

[root@centos7 scripts]# vim hello.sh
  1 #!/bin/bash
  2 #
  3 #***************************************
  4 #Author:        dong
  5 #QQ:            25448779
  6 #Date:          2020-12-26
  7 #FileName:      hello.sh
  8 #URL:           http://www.magedu.com
  9 #Description:   The test script
 10 #Copyright (C): 2020 All rights reserved
 11 #***************************************
 12

3.5 第一个脚本

3.5.1 第一个 Shell 脚本 hello world

[root@centos7 scripts]# vim hello.sh
  1 #!/bin/bash
  2 #
  3 #***************************************
  4 #Author:        dong
  5 #QQ:            25448779
  6 #Date:          2020-12-26
  7 #FileName:      hello.sh
  8 #URL:           http://www.magedu.com
  9 #Description:   The first script
 10 #Copyright (C): 2020 All rights reserved
 11 #***************************************
 12 #经典写法
 13 echo "hello, world"
 14 #流行写法
 15 echo 'Hello, world!'
 16

#执行方法1:没有执行权限时,使用bash .sh脚本来执行
[root@centos7 scripts]# bash hello.sh
hello, world
Hello, world!
#执行方法2
[root@centos7 scripts]# cat hello.sh |bash
hello, world
Hello, world!
#执行方法3
[root@centos7 scripts]# chmod +x hello.sh
#绝对路径
[root@centos7 ~]# /scripts/hello.sh
hello, world
Hello, world!
#相对路径
[root@centos7 ~]# cd /scripts
[root@centos7 scripts]# ./hello.sh
hello, world
Hello, world!
[root@centos7 scripts]# source hello.sh
hello, world
Hello, world!

#执行方法4,本方法可以实现执行远程主机的shell脚本
[root@web01 ~]# hostname -I
192.168.100.31
[root@web01 ~]# yum -y install nginx
[root@web01 ~]# nginx
[root@web01 ~]# cd /usr/share/nginx/html
[root@web01 html]# vim hello.sh

[root@centos7 scripts]# curl http://192.168.100.31/hello.sh|bash
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    42  100    42    0     0  11146      0 --:--:-- --:--:-- --:--:-- 21000
hello, world
Hello, world!
[root@centos7 scripts]# curl -s http://192.168.100.31/hello.sh|bash     #-s 隐藏下载的信息
hello, world
Hello, world!

[root@centos7 scripts]# wget -qO - http://192.168.100.31/hello.sh |bash
hello, world
Hello, world!

3.5.2 备份脚本实例

[root@centos7 scripts]# vim backup.sh
  1 #!/bin/bash
  2 #
  3 #***************************************
  4 #Author:        dong
  5 #QQ:            25448779
  6 #Date:          2020-12-26
  7 #FileName:      backup.sh
  8 #URL:           http://www.magedu.com
  9 #Description:   backup script
 10 #Copyright (C): 2020 All rights reserved
 11 #***************************************
 12
 13 echo -e "\033[1;31mReady to start backup...\033[0m"
 14 sleep 3
 15 cp -av /etc/ /data/etc`date +%F`/
 16 echo -e "\E[1;32mBackup is finished! \E[0m"

[root@centos7 scripts]# bash backup.sh
Ready to start backup...
‘/etc/’ -> ‘/data/etc2020-12-26/’
‘/etc/fstab’ -> ‘/data/etc2020-12-26/fstab’
...省略...
Backup is finished!

[root@centos7 scripts]# ll /data/etc2020-12-26/ -d
drwxr-xr-x. 77 root root 8192 Dec 26 09:39 /data/etc2020-12-26/
[root@centos7 scripts]# ll /data/etc2020-12-26/|wc
    188    1717   10943
[root@centos7 scripts]# ll /etc/ |wc
    188    1717   10943

3.6 shell 脚本调试

bash -n:只检测脚本中的语法错误,但无法检查出命令错误,不真正执行脚本。

bash -n /path/to/some_script

bash -x:调试并执行

bash -x /path/to/some_script

范例:

1)bash -n
[root@centos7 scripts]# vim test.sh
  1 #!/bin/bash
  2 #
  3 #***************************************
  4 #Author:        dong
  5 #QQ:            25448779
  6 #Date:          2020-12-26
  7 #FileName:      test.sh
  8 #URL:           http://www.magedu.com
  9 #Description:   The test script
 10 #Copyright (C): 2020 All rights reserved
 11 #***************************************
 12
 13 echo line1
 14 hostnam
 15 cat > test.txt <<EOF
 16 aaa
 17 bbb
 18 ccc
 19 EOF
 20
 21 echo line2

[root@centos7 scripts]# bash -n test.sh
test.sh: line 22: warning: here-document at line 15 delimited by end-of-file (wanted `EOF')

#执行时提示错误信息,通过cat -A查看隐藏字符
[root@centos7 scripts]# cat -A test.sh
echo line1$
hostnam$
cat > test.txt <<EOF $
aaa$
bbb$
ccc$
EOF $
$
echo line2$
$
#也可以在vim中查看
[root@centos7 scripts]# vim test.sh
 13 echo line1$
 14 hostnam$
 15 cat > test.txt <<EOF $
 16 aaa$
 17 bbb$
 18 ccc$
 19 EOF $
 20 $
 21 echo line2$
 22 $

:set list  ##vim编辑器里,使用set list也可以查看隐藏字符

#提示信息为界定符的问题,查看到第19行的EOF结尾有个空格,将其删除后正常
[root@centos7 scripts]# bash -n test.sh
[root@centos7 scripts]#

2)bash -x
#但执行的时候,提示命令错误信息,-n选项检查不出来,这就需要-x选项
[root@centos7 scripts]# bash test.sh
line1
test.sh: line 14: hostnam: command not found
line2
# bash -x选项,边调试边执行
[root@centos7 scripts]# bash -x test.sh
+ echo line1
line1
+ hostnam
test.sh: line 14: hostnam: command not found    #检查出命令错误信息
+ cat
+ echo line2
line2

总结:脚本错误常见的有三种

  • 语法错误:会导致后续的命令不继续执行,可以用bash -n 检查错误,提示的出错行数不一定是准确的
  • 命令错误:默认后续的命令还会继续执行,用bash -n 无法检查出来 ,可以使用 bash -x 进行观察
  • 逻辑错误:只能使用 bash -x 进行观察

3.7 变量

3.7.1 变量

变量表示命名的内存空间,将数据放在内存空间中,通过变量名引用来获取数据。

3.7.2 变量类型

1、变量类型:

内置变量:如:PS1,PATH,UID,HOSTNAME,$$,BASHPID,PPID,$?,HISTSIZE

用户自定义变量:

不同的变量存放的数据不同,决定了:

  1. 数据存储方式
  2. 参与的运算(数学运算、字符相连或取字符串的一部分)
  3. 表示的数据范围

2、变量数据类型:

  • 字符
  • 数值:整型、浮点型,bash 不支持浮点数

3.7.3 编程语言分类

1、静态和动态语言

  • 静态编译语言:使用变量前,先声明变量类型,之后类型不能改变,在编译时检查,如:java,c
  • 动态编译语言:不用事先声明,可随时改变类型,如:bash,Python

2、强类型和弱类型语言

强类型语言:不同类型数据操作,必须经过强制转换成同一类型才能运算,如java , c# ,python

如:参考以下 python 代码

print('magedu'+ 10) 提示出错,不会自动转换类型

print('magedu'+str(10)) 结果为magedu10,需要显示转换类型

弱类型语言:语言的运行时会隐式做数据类型转换。无须指定类型,默认均为字符型;参与运算会

自动进行隐式类型转换;变量无须事先定义可直接调用

如:bash ,php,javascript

3.7.4 Shell中变量命名法则

  • 不能使程序中的保留字(关键字):如:if, for
  • 只能使用数字、字母及下划线,且不能以数字开头,注意:不支持短横线 “ - ”,和主机名相反
  • 见名知义,用英文单词命名,并体现出实际作用,不要用简写,如:ATM
  • 统一命名规则:驼峰命名法, studentname,大驼峰StudentName 小驼峰studentName
  • 变量名大写:STUDENT_NAME
  • 局部变量小写
  • 函数名小写

3.7.5 变量定义和引用

变量的生效范围等标准来划分变量类型。

  • 普通变量:生效范围为当前shell进程;对当前shell之外的其它shell进程,包括当前shell的子shell进程均无效
  • 环境变量:生效范围为当前shell进程及其子进程
  • 本地变量:生效范围为当前shell进程中某代码片断,通常指函数

变量赋值:

name='value'

#value 可以是以下多种形式
直接字串:name='root'
变量引用:name="$USER"
命令引用:name=`COMMAND` 或者 name=$(COMMAND)

#赋值前后不能有空格,都会报错
TITLE ='cto'
TITLE= 'cto'
TITLE = 'cto'

[root@centos7 scripts]# TITLE ='cto'
-bash: TITLE: command not found
[root@centos7 scripts]# TITLE= 'cto'
-bash: cto: command not found
[root@centos7 scripts]# TITLE = 'cto'
-bash: TITLE: command not found
[root@centos7 scripts]# TITLE='cto'
[root@centos7 scripts]# echo $TITLE
cto

==注意:变量赋值是临时生效,当退出终端后,变量会自动删除,无法持久保存,脚本中的变量会随着脚本结束,也会自动删除。==

变量引用:

$name
${name}

弱引用和强引用:

  • "$name " 弱引用,其中的变量引用会被替换为变量值
  • '$name ' 强引用,其中的变量引用不会被替换为变量值,而保持原字符串

范例:变量的各种赋值方式和引用

[root@centos7 scripts]# TITLE='cto'
[root@centos7 scripts]# echo $TITLE
cto
[root@centos7 scripts]# echo I am $TITLE
I am cto
[root@centos7 scripts]# echo "I am $TITLE"      #弱引用
I am cto    
[root@centos7 scripts]# echo 'I am $TITLE'      #强引用
I am $TITLE
[root@centos7 scripts]# NAME=$USER              #内建的环境变量USER,默认显示当前用户root
[root@centos7 scripts]# echo $NAME
root
[root@centos7 scripts]# USER=`hostname`         #修改USER的变量为`hostname`
[root@centos7 scripts]# echo $USER
centos7
[root@centos7 scripts]# echo ${USER}
centos7

[root@centos7 scripts]# FILE=`ls /run`
[root@centos7 scripts]# echo $FILE
auditd.pid chrony console crond.pid cron.reboot cryptsetup dbus dmeventd-client dmeventd-server faillock initramfs lock log lvm lvmetad.pid mount netreport NetworkManager plymouth sepermit setrans sshd.pid sudo syslogd.pid systemd tmpfiles.d tuned udev user utmp vmware

[root@centos7 scripts]# FILE=/etc/
[root@centos7 scripts]# echo $FILE
/etc/
[root@centos7 scripts]# FILE=/etc/*
[root@centos7 scripts]# echo $FILE  
/etc/adjtime /etc/aliases /etc/aliases.db /etc/alternatives /etc/anacrontab /etc/asound.conf /etc/audisp /etc/audit /etc/bash_completion.d /etc/bashrc /etc/binfmt.d /etc/centos-release ...省略...

[root@centos7 scripts]# seq 10
1
2
3
4
5
6
7
8
9
10
[root@centos7 scripts]# NUM=`seq 10`
[root@centos7 scripts]# echo $NUM
1 2 3 4 5 6 7 8 9 10
[root@centos7 scripts]# echo "$NUM"
1
2
3
4
5
6
7
8
9
10

[root@centos7 scripts]# NAMES="wang
> zhang
> zhao
> li"
[root@centos7 scripts]# echo $NAMES
wang zhang zhao li
[root@centos7 scripts]# echo "$NAMES"
wang
zhang
zhao
li

范例:变量引用

[root@centos7 scripts]# NAME=mage
[root@centos7 scripts]# AGE=20
[root@centos7 scripts]# echo $NAME $AGE
mage 20
[root@centos7 scripts]# echo $NAME$AGE
mage20
[root@centos7 scripts]# echo $NAME-$AGE
mage-20
[root@centos7 scripts]# echo $NAME:$AGE
mage:20
[root@centos7 scripts]# echo $NAME_$AGE
20
[root@centos7 scripts]# echo ${NAME}_$AGE
mage_20

范例:变量的间接赋值和引用

[root@centos7 scripts]# TITLE=cto
[root@centos7 scripts]# NAME=wang
[root@centos7 scripts]# TITLE=$NAME
[root@centos7 scripts]# echo $NAME
wang
[root@centos7 scripts]# echo $TITLE
wang
[root@centos7 scripts]# NAME=mage       ##NAME赋新值
[root@centos7 scripts]# echo $NAME
mage
[root@centos7 scripts]# echo $TITLE     ##而TITLE还是原来的赋值
wang
[root@centos7 scripts]# TITLE=$NAME
[root@centos7 scripts]# echo $TITLE     ##再次给TITLE赋值,也变成新的值了
mage

范例:变量追加值

[root@centos7 scripts]# TITLE=CTO
[root@centos7 scripts]# TITLE+=:wang
[root@centos7 scripts]# echo $TITLE
CTO:wang

范例:利用变量实现动态命令

[root@centos7 scripts]# CMD=hostname
[root@centos7 scripts]# $CMD            ##相当于执行hostname命令
centos7
[root@centos7 scripts]# echo $CMD
hostname

显示已定义的所有变量:

set

范例:

[root@centos7 scripts]# set     ##当前系统下设置的所有变量(含临时变量)
AGE=20
BASH=/bin/bash
BASHOPTS=checkwinsize:cmdhist:expand_aliases:extquote:force_fignore:histappend:hostcomplete:interactive_comments:login_shell:progcomp:promptvars:sourcepath
CMD=hostname
FILE='/etc/*'
GROUPS=()
HISTCONTROL=ignoredups
HISTFILE=/root/.bash_history
HISTFILESIZE=1000
HISTSIZE=1000
HOME=/root
HOSTNAME=centos7
HOSTTYPE=x86_64
LS_COLORS='rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=01;05;37;'
MAIL=/var/spool/mail/root
NAME=mage
NAMES=$'wang\nli\nzao\nzhang'
NUM=$'1\n2\n3\n4\n5\n6\n7\n8\n9\n10'
OLDPWD=/root
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
PPID=1230
TITLE=CTO:wang
UID=0
USER=centos7
colors=/root/.dircolors

删除变量:

unset <name>

范例:

[root@centos7 scripts]# NAME=mage
[root@centos7 scripts]# TITLE=ceo
[root@centos7 scripts]# echo $NAME $TITLE
mage ceo
[root@centos7 scripts]# unset $NAME         ##unset+name,不加$
[root@centos7 scripts]# echo $NAME
mage
[root@centos7 scripts]# unset NAME TITLE
[root@centos7 scripts]# echo $NAME $TITLE

3.7.6 实例:显示系统信息

1、编写脚本 systeminfo.sh,显示当前主机系统信息,包括:主机名,IPv4地址,操作系统版本,内核
版本,CPU型号,内存大小,硬盘大小。

[root@centos7 scripts]# vim systeminfo.sh
  1 #!/bin/bash
  2 #
  3 #***************************************
  4 #Author:        dong
  5 #QQ:            25448779
  6 #Date:          2020-12-26
  7 #FileName:      systeminfo.sh
  8 #URL:           http://www.magedu.com
  9 #Description:   The systeminfo script
 10 #Copyright (C): 2020 All rights reserved
 11 #***************************************
 12
 13 RED="\E[1;31m"
 14 GREEN="\E[1;32m"
 15 END="\E[0m"
 16 echo -e "$GREEN----------------Host systeminfo---------------$END"
 17 echo -e "HOSTNAME: $RED`hostname`$END"
 18 echo -e "IPADDR: $RED`ifconfig ens33|grep -Eo '([0-9]{1,3}.){3}[0-9]{1,3}'|head -1`$END"
 19 echo -e "OSVERSION: $RED`cat /etc/redhat-release`$END"
 20 echo -e "KERNEL: $RED`uname -r`$END"
 21 echo -e "CPU: $RED`cat /proc/cpuinfo|grep 'model name'|cut -d: -f2`$END"
 22 echo -e "TOTAL MEMORY: $RED`free -h|grep 'Mem'|tr -s ' ' :|cut -d: -f2`$END"
 23 echo -e "DISK: $RED`lsblk|grep '^sd'|tr -s ' ' :|cut -d: -f5`$END"
 24 echo -e "$GREEN----------------------------------------------$END"

[root@centos7 scripts]# bash systeminfo.sh
----------------Host systeminfo---------------
HOSTNAME: centos7
IPADDR: 192.168.100.11
OSVERSION: CentOS Linux release 7.8.2003 (Core)
KERNEL: 3.10.0-1127.13.1.el7.x86_64
CPU:  Intel(R) Core(TM) i5-4210U CPU @ 1.70GHz
TOTAL MEMORY: 972M
DISK: 20G
----------------------------------------------

2、编写脚本 backup.sh,可实现每日将/etc/目录备份到/backup/etcYYYY-mm-dd中

[root@centos7 scripts]# vim backup.sh
  1 #!/bin/bash
  2 #
  3 #***************************************
  4 #Author:        dong
  5 #QQ:            25448779
  6 #Date:          2020-12-26
  7 #FileName:      backup.sh
  8 #URL:           http://www.magedu.com
  9 #Description:   backup script
 10 #Copyright (C): 2020 All rights reserved
 11 #***************************************
 12
 13 echo -e "\033[1,32mReady to start backup...\033[0m"
 14 sleep 3
 15 cp -av /etc/ /backup/etc`date +%F`/
 16 echo -e "\E[1,31mBackup is finished! \E[0m"

[root@centos7 scripts]# bash backup.sh
Ready to start backup...
‘/etc/’ -> ‘/backup/etc2020-12-26/’
‘/etc/fstab’ -> ‘/backup/etc2020-12-26/fstab’
...省略...
Backup is finished!
[root@centos7 scripts]# ll /backup/etc2020-12-26/ -d
drwxr-xr-x. 77 root root 8192 Dec 26 09:39 /backup/etc2020-12-26/
[root@centos7 scripts]# ll /backup/etc2020-12-26/|wc
    188    1717   10943
[root@centos7 scripts]# ll /etc/ |wc
    188    1717   10943

3、编写脚本 disk.sh,显示当前硬盘分区中空间利用率最大的值

[root@centos7 scripts]# vim disk.sh
  1 #!/bin/bash
  2 #
  3 #***************************************
  4 #Author:        dong
  5 #QQ:            25448779
  6 #Date:          2020-12-26
  7 #FileName:      disk.sh
  8 #URL:           http://www.magedu.com
  9 #Description:   Maximum disk utilization
 10 #Copyright (C): 2020 All rights reserved
 11 #***************************************
 12
 13 echo -e "Maximum disk utilization:\E[1;31m`df -h|tail -n +2|tr -s ' ' %|cut -d% -f5|sort -nr|head -1`\E[0m"

[root@centos7 scripts]# bash disk.sh
Maximum disk utilization:22

4、编写脚本 links.sh,显示正连接本主机的每个远程主机的IPv4地址和连接数,并按连接数从大到小排序。

[root@centos7 scripts]# vim link.sh
  1 #!/bin/bash
  2 #
  3 #***************************************
  4 #Author:        dong
  5 #QQ:            25448779
  6 #Date:          2020-12-26
  7 #FileName:      disk.sh
  8 #URL:           http://www.magedu.com
  9 #Description:   Remote access host
 10 #Copyright (C): 2020 All rights reserved
 11 #***************************************
 12
 13 echo -e "Remote access reserved:\n\E[1;31m`ss -nt|grep ^ESTAB|tr -s ' ' :|cut -d: -f6|sort|uniq -c|sort -nr`\E[0m"

[root@centos7 scripts]# bash link.sh
Remote access reserved:
      7 192.168.100.1
      1 192.168.100.31

猜你喜欢

转载自blog.51cto.com/puppydong/2573972