侧边栏壁纸
博主头像
张种恩的技术小栈博主等级

行动起来,活在当下

  • 累计撰写 748 篇文章
  • 累计创建 65 个标签
  • 累计收到 39 条评论

目 录CONTENT

文章目录

Linux基础(21)之grep入门使用

zze
zze
2019-10-22 / 0 评论 / 0 点赞 / 384 阅读 / 9246 字

不定期更新相关视频,抖音点击左上角加号后扫一扫右方侧边栏二维码关注我~正在更新《Shell其实很简单》系列

grep介绍

Linux 中的 grep 命令用于查找文件里符合条件的字符串。
grep 全称为 Global search REgular expression and Print out the line,用于查找内容包含指定的范本样式的文件,如果发现某文件的内容符合所指定的范本样式,预设 grep 指令会把含有范本样式的那一列显示出来。若不指定任何文件名称,或是所给予的文件名为 -,则 grep 指令会从标准输入设备读取数据。
grep 命令能够使用模式(pattern)来匹配一个指定文件中的每一行文本,输出匹配到的行。

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

正则表达式(REGEXP)

由一类特殊字符及文本字符所编写的模式,其中有些字符不表示字符字面意义,而表示控制或通配的功能。
正则表达式又分如下两类:

  1. 基本正则表达式(BRE);
  2. 扩展正则表达式(ERE);

grep 又分为 grepegrepfgrep

  • grep 支持基本正则表达式;
  • egrep 支持扩展正则表达式。
  • fgrep 支持快速匹配,不支持正则表达式。

基本正则表达式元字符

字符匹配:

  • . :匹配任意单个字符;
  • [] :匹配指定范围内的单个字符;
  • [^] :匹配指定范围之外的单个字符;
  • [:digit:] :匹配数字;
  • [:lower:] :匹配所有小写字符;
  • [:upper:] :匹配所有大写字符;
  • [:alpha:] : 匹配任意字母;
  • [:alnum:] :匹配所有的字幕和数字;
  • [:punct:] :匹配所有的标点符号;
  • [:space:] :匹配空白字符;

例 1:输出以 r 开头 t 结尾且中间包含了 2 个任意字符的字符串。

image.png

例 2:输出 /etc/passwd 文件中包含的数字。

image.png

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

  • * :仅表示次数,表示前面的字符可以出现任何次数;
  • .* :任意长度的任意字符;
  • \? :前面的字符可以出现 0 次或 1 次;
  • \+ :前面字符至少出现 1 次;
  • \{m\} :匹配前面的字符 m 次;
  • \{m,n\} :匹配前面的字符至少 m 次,至多 n 次;

例:输出 /etc/passwd 中前 3 位为小写字母,后 1 位为 t 的字符串。

image.png

位置锚定:

  • ^ :行首锚定,出现在模式的最左侧;
  • $ :行尾锚定,出现在模式的最右侧;
  • ^$ :匹配空行;
  • \<\b :词首锚定,表示匹配字符必须出现正在单词的首部,用于单词模式的左侧;
  • \>\b :词尾锚定,表示匹配字符必须出现在单词的尾部,用于单词模式的右侧;
  • \<PATTERN\> :匹配整个单词;

分组:

  • \(\):将一个或多个字符当做一个整体进行处理;

在分组的知识点中有一个后向引用的功能,它的作用是引用前面分组括号中的模式所匹配到的字符,而非模式本身。
例:输出 /etc/passwdroot 出现过 2 次的行。

image.png

分组括号中的模式匹配到的内容会被正则表达式引擎记录与内部的变量中,这些变量的命名方式为 \1\2\3 ... 、\n
\n 表示从左侧起,第 n 个左括号以及与之匹配的右括号之间的模式所匹配到的字符。
即在该示例中通过 \1 引用了前面分组括号中的 root 匹配到的内容。

如果模式中出现元字符,通常要使用引号引起来,单引号为强引用,双引号为弱引用,这意味着如果双引号中有变量的话会先将该变量替换成对应值后再进行匹配。

grep使用

格式:

grep [OPTIONS] PATTERN [FILE...]
grep [OPTIONS] [-e PATTERN | -f FILE] [FILE...]

例:输出 /etc/passwd 中包含 root 的行。

image.png

如果匹配时只是使用基本字符不需要使用正则表达式,推荐使用 fgrep 效率更高(因为 fgrep 不会调用正则表达式引擎)。

image.png

在 CentOS 6 中的匹配结果默认是没有关键字着色的,但是可以通过选项 --color=auto 来指定关键字着色,实际上在 CentOS 7 中也是通过别名来指定了该选项的,如:alias grep='grep --color=auto'

grep 命令还可以通过 -v 选项来指定显示未匹配到的行。
例:输出 /etc/passwd 中不包含 root 的行。

[root@localhost testDir]# fgrep root /etc/passwd -v
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
...

grep 命令还有几个分别对应 grepegrepfgrep 的选项;

  • grep -G:相当于直接使用 grep 命令,仅支持基本正则表达式;
  • grep -E:相当于使用 egrep,支持扩展正则表达式;
  • grep -F:相当于使用 fgrep,不支持正则表达式;

还可以通过 -A 选项来制定输出匹配到的内容后 n 行。
例:输出 /etc/passwd 中包含 root 的行及后 1 行。

image.png

-A 选项类似的还有 -B-C-B 选项是用来指定显示输出匹配到的行和前 n 行,而 -C 选项是用来指定输出匹配到的行及前后各 n 行。
还有一些常用选项如下:

  • -i 选项来指定匹配时忽略大小写,这个很容易理解就不演示。
  • -o 选项来指定只显示匹配到的字符串,而不是匹配到的整行内容。
  • -q 选项来指定开启静默模式,意思是不输出任何信息,只需要通过 $? 来获取是否匹配成功,匹配成功 $? 的值为 0,而匹配失败 $? 的值则为 1

练习

1、显示 /proc/meminfo 文件中以 s 开头不区分大小写的行(要求使用 2 种方式)。
方式一:可通过 grep 命令的 -i 选项指定首个字符不区分大小写。

image.png

方式二:可通过 [Ss] 限定首个字符只能为 sS

image.png

2、显示 /etc/passwd 文件中不以 /bin/bash 结尾的行。
思路:可以先找到以 /bin/bash 结尾的行,然后通过 -v 选项取反。

image.png

3、显示 /etc/passwd 文件中 ID 号最大的用户的用户名。
思路:可通过 sort 命令先按 id 号对应的列值大小进行排序,取排序后结果最后一条中的用户名即可。

[root@localhost ~]# sort -t: -k3 -n /etc/passwd | tail -1 | cut -d: -f1
polkitd

4、如果用户 root 存在,显示其默认的 shell 程序。
思路:可先通过 id 命令查看指定用户存在不存在,如果存在,则取出 /etc/passwd 文件中对应用户行的 shell 描述列。

[root@localhost ~]# id root &> /dev/null && grep '^root\>' /etc/passwd | cut -d: -f7
/bin/bash

5、找出 /etc/passwd 中的两位或三位数。
思路:可先限定匹配的数字范围,然后通过 \{2,3\} 来指定数字出现的次数。

[root@localhost ~]# grep '\<[0-9]\{2,3\}\>' /etc/passwd -o
12
11
12
100
14
50
...

6、显示 /etc/grub2.cfg 文件中,至少以一个空白字符开头的且后面存在非空白字符的行。
思路:可通过 [[:space:]] 来匹配空白字符,通过 [^[:space:]] 来匹配非空白字符。

[root@localhost ~]# grep '^[[:space:]]\+[^[:space:]]' /etc/grub2.cfg 
  load_env
   set default="${next_entry}"
   set next_entry=
   save_env next_entry
   set boot_once=true
...

7、找出 netstat -tan 命令的结果中以 LISTEN 后跟 0 或多个空白字符结尾的行。

[root@zze ~]# netstat -tan | grep 'LISTEN[[:space:]]*$'
tcp        0      0 0.0.0.0:22                  0.0.0.0:*                   LISTEN      
tcp        0      0 :::3306                     :::*                        LISTEN      
tcp        0      0 :::22                       :::*                        LISTEN  

8、添加用户 bashtestbashbasher 以及 nologin(其 shell 为 /sbin/nologin),而后找出 /etc/passwd 文件中用户名同 shell 名的行。
思路:先找出开头的用户名使用 \(\) 分组,然后通过后向引用指定以它结尾。

[root@localhost ~]# useradd bash
[root@localhost ~]# useradd basher
[root@localhost ~]# useradd testbash
[root@localhost ~]# useradd -s /sbin/nologin nologin
[root@localhost ~]# grep '^\<\([[:alnum:]]\+\)\>.*\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
bash:x:1000:1000::/home/bash:/bin/bash
nologin:x:1003:1003::/home/nologin:/sbin/nologin

9、写一个脚本,实现如下功能:

  • 如果 user1 存在,就显示其存在,否则添加之;
  • 显示添加的用户的 id 号等信息;

新建脚本 user1.sh,内容如下:

#!/bin/bash
id user1 &> /dev/null && echo '已存在' || useradd user1
id user1

给与它执行权限,执行:

[root@localhost ~]# chmod +x user1.sh 
[root@localhost ~]# ./user1.sh 
uid=1004(user1) gid=1004(user1) 组=1004(user1)

10、写一个脚本,完成如下功能:

  • 如果 root 用户登录了当前系统,就显示 root 用户在线;
  • 否则输出其未登录;
    新建脚本 rootislogged.sh 内容如下:
#!/bin/bash
w | grep 'root\>' &> /dev/null && echo '已登录' || echo '未登录'

给与其运行权限,运行:

[root@localhost ~]# chmod +x rootislogged.sh
[root@localhost ~]# ./rootislogged.sh 
已登录
0

评论区