Shell 三剑客之 grep

1. grep 概述

1.1 grep 是什么

在我们日常 Linux 运维过程中,最多的就是对 Linux 文件进行处理,grep(global search regular expression (RE) and print out the line)作为一款非常方便且强大的文本搜索工具,其能使用正则表达式搜索文本,并把匹配的行打印出来,其使用对象为 Linux 系统的所有用户,使得我们日常操作更加方便简单。

1.2 为什么要用 grep

在 Linux 系统中一切皆文件,我们日常的工作就是与文件打交道,能够运用 grep 这款文件搜索工具,可以大大提高我们的工作效率,我们上节课学习了正则表达式,grep 配合正则表达式能够作出 1+1 大于 2 的效果,灵活使用使得我们的工作更加高效快捷。

2. grep 详解

2.1 grep 分类

Unix 的 grep 家族包括 grep、egrep 和 fgrep。egrep 和 fgrep 的命令跟 grep 只有很小不同。

  • egrep 是 grep 的扩展,其支持更多 re 元字符,和扩展正则表达式等。
  • fgrep 就是 fixed grep 或 fast grep,它们把所有的字母都看作单词,也就是说,正则表达式中的元字符表示其自身的字面意义,不再特殊。
  • linux 使用 GNU 版本的 grep。它功能更强,可以通过 - G、-E、-F 命令行选项来使用 egrep 和 fgrep 的功能。

2.2 grep 工作方式

grep 的工作方式为将一个或多个文件中搜索字符串模版。如果模版包括空格,则必须被引用,模板后的所有字符串被看作文件名。搜索的结果被送到屏幕,不影响原文件内容。

grep 命令结束后通过一个状态值来说明搜索状态,如果为 0 则意味着搜索成功,反之则为失败,我们可以利用其对文件自动化处理。

2.3 grep 语法

grep [OPTION]... PATTERN [FILE]

其中 OPTION 有很多方式,例如 - A3 表示显示符合范本样式的那一行之外,并显示该行之后的 3 行内容。

PATTERN 表示:匹配的模式,通常为一个表达式。

FilE 为具体的需要处理的问题,当然也可以为标准输入。

2.3 参数详解

在上一节中我们详细讲解了正则表达式,它就可以用在 grep 命令的 PATTERN 字段中,使得 grep 更加强大,本章节我们着重来讲解 grep 命令的 OPTION

不加参数,匹配 /etc/passwd 文件中的 root 行,例如:

[root@master grep]# grep "root" /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
  • -A:显示模式匹配后的几行

查找 /etc/passwd 文件中以 root 开头的后两行,例如:

[root@master grep]# grep -A2 "^root" /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
  • -B:显示模式匹配行的前几行

查找 /etc/passwd 文件中以 bin 开头的前一行,例如:

[root@master grep]# grep -B1 "^bin" /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
  • -C:显示模式匹配的前后各几行

查找 /etc/passwd 文件中以 ftp 开头的前后各 2 行,例如:

[root@master grep]# grep -C2 "^ftp" /etc/passwd     
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
  • -i:忽略大小写匹配

匹配 /etc/passwd 包含 "Nobody" 的行,例如:

[root@master grep]# grep -i "Nobody" /etc/passwd
nobody:x:99:99:Nobody:/:/sbin/nologin
nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin
  • -o :只显示匹配到的字符串

匹配出 /etc/passwd 文件中字符串长度最少 10 位的字符 ,例如:

[root@master grep]# grep -o "[[:alnum:]]\{10,\}" /etc/passwd
Management
Kubernetes
  • -n:输出匹配到的行的行号

匹配出 /etc/passwd 文件中包含 root 的字符串的行,例如:

[root@master grep]# grep -n "root" /etc/passwd
1:root:x:0:0:root:/root:/bin/bash
10:operator:x:11:0:operator:/root:/sbin/nologin
  • -v:反向选择,即显示除过 匹配’搜寻字符串’ 内容的那一行

匹配出 /etc/passwd 中不包含 bash 的行,例如:

[root@master grep]# grep -v "nologin" /etc/passwd    
root:x:0:0:root:/root:/bin/bash
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
  • -c : 计算找到 ‘搜寻字符串’ 的次数

计算 /etc/passwd 文件中 root 字符串出现的次数,例如:

[root@master grep]# grep -c "root" /etc/passwd
2
  • -E: 开启正则表达式,相当于使用命令 egrep

查找 /etc/passwd 文件中包含三位数字的行,例如:

[root@master grep]# grep -E "[[:digit:]]{3}" /etc/passwd
games:x:12:100:games:/usr/games:/sbin/nologin
systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
polkitd:x:999:997:User for polkitd:/:/sbin/nologin
ceph:x:167:167:Ceph daemons:/var/lib/ceph:/sbin/nologin
kube:x:998:996:Kubernetes user:/home/kube:/sbin/nologin
etcd:x:997:993:Etcd user:/var/lib/etcd:/bin/nologin
gluster:x:996:992:GlusterFS daemons:/run/gluster:/sbin/nologin
nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin
chrony:x:995:991::/var/lib/chrony:/sbin/nologin
redis:x:994:990:Redis Database Server:/var/lib/redis:/sbin/nologin

3. 实例

3.1 需求

编写一个脚本,获取 Linux 系统的服务信息,将结果保存到文件中。

3.2 思路

可以利用函数来编写获取 Linux 服务相关信息,最后利用重定向将信息输出到文件中。

3.3 实现

#!/bin/bash
# Description: service check
# Auth: kaliarch
# Email: kaliarch@163.com
# function: sys check
# Date: 2020-04-11 14:00
# Version: 1.0

[ $(id -u) -gt 0 ] && echo "请用root用户执行此脚本!" && exit 1
sysversion=$(rpm -q centos-release|cut -d- -f3)
line="-------------------------------------------------"


[ -d logs ] || mkdir logs

service_check_file="logs/service-`date +%Y%m%d`.txt"

# 获取服务信息
function get_service_info() {
    port_listen=$(netstat -lntup|grep -v "Active Internet")
    kernel_config=$(sysctl -p 2>/dev/null)
    if [ ${sysversion} -gt 6 ];then
        service_config=$(systemctl list-unit-files --type=service --state=enabled|grep "enabled")
        run_service=$(systemctl list-units --type=service --state=running |grep ".service")
    else
        service_config=$(/sbin/chkconfig | grep -E ":on|:启用" |column -t)
        run_service=$(/sbin/service --status-all|grep -E "running")
    fi
cat <<EOF
服务启动配置:
${service_config}
${line}
运行的服务:
${run_service}
${line}
监听端口:
${port_listen}
${line}
内核参考配置:
${kernel_config}
EOF
}


function sys_check() {
    get_service_info
    echo ${line}
}




# 执行主函数将输出重定向到文件中
sys_check > ${sys_check_file}

# 执行测试
[root@xuel-terraform-cvm-0 ~]# bash sys_check.sh
[root@xuel-terraform-cvm-0 ~]# cat logs/10.0.1.15-20200329.txt
[root@master grep]# cat logs/service-20200411.txt 
服务启动配置:
auditd.service                              enabled
autovt@.service                             enabled
ceph-mon@.service                           enabled
ceph-osd@.service                           enabled
chronyd.service                             enabled
crond.service                               enabled
dbus-org.freedesktop.NetworkManager.service enabled
dbus-org.freedesktop.nm-dispatcher.service  enabled
docker.service                              enabled
etcd.service                                enabled
gapd.service                                enabled
getty@.service                              enabled
irqbalance.service                          enabled
kdump.service                               enabled
kubelet.service                             enabled
microcode.service                           enabled
NetworkManager-dispatcher.service           enabled
NetworkManager.service                      enabled
postfix.service                             enabled
rpcbind.service                             enabled
rsyslog.service                             enabled
smarteye-server-agent.service               enabled
sshd.service                                enabled
systemd-readahead-collect.service           enabled
systemd-readahead-drop.service              enabled
systemd-readahead-replay.service            enabled
tuned.service                               enabled
-------------------------------------------------
运行的服务:
auditd.service                loaded active running Security Auditing Service
ceph-mon@master.service       loaded active running Ceph cluster monitor daemon
ceph-osd@0.service            loaded active running Ceph object storage daemon
chronyd.service               loaded active running NTP client/server
crond.service                 loaded active running Command Scheduler
dbus.service                  loaded active running D-Bus System Message Bus
docker.service                loaded active running Docker Application Container Engine
etcd.service                  loaded active running etcd docker wrapper
gapd.service                  loaded active running guest agent for pitrix
getty@tty1.service            loaded active running Getty on tty1
gssproxy.service              loaded active running GSSAPI Proxy Daemon
irqbalance.service            loaded active running irqbalance daemon
kubelet.service               loaded active running Kubernetes Kubelet Server
NetworkManager.service        loaded active running Network Manager
polkit.service                loaded active running Authorization Manager
postfix.service               loaded active running Postfix Mail Transport Agent
rpcbind.service               loaded active running RPC bind service
rsyslog.service               loaded active running System Logging Service
smarteye-server-agent.service loaded active running The Smarteye Monitoring of server
sshd.service                  loaded active running OpenSSH server daemon
systemd-journald.service      loaded active running Journal Service
systemd-logind.service        loaded active running Login Service
systemd-udevd.service         loaded active running udev Kernel Device Manager
tuned.service                 loaded active running Dynamic System Tuning Daemon
-------------------------------------------------
监听端口:
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 127.0.0.1:9099          0.0.0.0:*               LISTEN      10444/calico-node   
tcp        0      0 172.16.60.2:2379        0.0.0.0:*               LISTEN      1321/etcd            
tcp6       0      0 :::9353                 :::*                    LISTEN      2058/node-cache     
udp        0      0 0.0.0.0:37811           0.0.0.0:*                           610/dhclient        
udp        0      0 169.254.25.10:53        0.0.0.0:*                           2058/node-cache     
udp        0      0 0.0.0.0:68              0.0.0.0:*                           610/dhclient        
udp        0      0 0.0.0.0:111             0.0.0.0:*                           1/systemd           
udp        0      0 0.0.0.0:123             0.0.0.0:*                           530/chronyd         
udp        0      0 127.0.0.1:323           0.0.0.0:*                           530/chronyd         
udp        0      0 0.0.0.0:703             0.0.0.0:*                           535/rpcbind         
udp6       0      0 :::35267                :::*                                610/dhclient        
udp6       0      0 :::111                  :::*                                1/systemd           
udp6       0      0 ::1:323                 :::*                                530/chronyd         
udp6       0      0 :::703                  :::*                                535/rpcbind         
-------------------------------------------------
内核参考配置:
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_local_reserved_ports = 30000-32767
net.bridge.bridge-nf-call-arptables = 1
-------------------------------------------------

可以看到利用了一个函数来获取系统的信息,主函数将输出利用重定向方式保存到文件中。

4. 注意事项

  • grep 对于文件搜索效率非常高,其不会对源文件作出修改;
  • 默认 Linux 系统 grep 可以使用参数 - E,-F 来使用 egrep/fgrep;
  • 对于复杂的条件可以利用 grep 配合管道多匹配来达到目的。

5. 小结

grep 命令是 Linux 系统非常强大的文本搜索工具,可以配合正则表达式及其丰富的选项来灵活处理,同时对于复杂的文件搜索,可以配合管道多次匹配来达到搜索的目的,特殊情况下可以利用选项 - E,开启正则表达式来提供强大的模式匹配处理。