linux三剑客grep、sed和AWK的功能十分强大,用好这三个工具,可以显著提高运维的效率,本文记录了运维过程中如何使用这三个工具,主要是备查,各位的运维小伙伴也可以参考参考。
1 使用脚本创建示例文件及文件显示
[root@iZuf6b1znamggglbunalhzZ ~]# for i in $(seq 1 10);do echo $i >>test.txt;done;
[root@iZuf6b1znamggglbunalhzZ ~]# cat test.txt
1
2
3
4
5
6
7
8
9
10
上面的脚本用的是for循环,seq命令打印一个数字序列,这个脚本,是不是可以写得更简单一点,当然可以,不用for循环,直接写成seq 1 10 》 testtxt 结果也是一样的,
linux bshell的写法非常灵活这个for循环也可以写成另一种形式
for i in `seq 1 10`;do echo $i >>test.txt; done;
` `里面可以换成其它shell命令,比如换成ls -l
[root@iZ2ze0t8khaprrpfvmevjiZ ~]# for i in `ls `; do echo $i ;done;
my_oss
mysql-5.7.34-linux-glibc2.12-x86_64.tar.gz
oracle-database-ee-21c-1.0-1.ol8.x86_64.rpm
oracle-database-preinstall-21c-1.0-1.el8.x86_64.rpm
test.txt
这里的for循环用的是列表形式,for循环里的循环体可以写的得更复杂一下,比如在前面和后面加上一些字符串
[root@iZ2ze0t8khaprrpfvmevjiZ ~]# for i in $(seq 1 10);do echo test $i":this is test1" >>test.txt;done;
[root@iZ2ze0t8khaprrpfvmevjiZ ~]# cat test.txt
test 1:this is test1
test 2:this is test1
test 3:this is test1
test 4:this is test1
test 5:this is test1
test 6:this is test1
test 7:this is test1
test 8:this is test1
test 9:this is test1
test 10:this is test1
清空一个文本文件可以直接删除,如果要保留文件只是清空里面的内容,可以拷贝或移动空文件至目标文件,比如用cp命令
[root@iZ2ze0t8khaprrpfvmevjiZ ~]# cp /dev/null test.txt
cp: overwrite 'test.txt'? y
[root@iZ2ze0t8khaprrpfvmevjiZ ~]# cat /dev/null
cat还有一些有用的选型,比如-n选项可以在每行的左边显示行号
[root@iZuf6b1znamggglbunalhzZ ~]# cat -n /var/log/messages|head -10
1 Nov 30 15:31:43 iZuf6b1znamggglbunalhzZ systemd: Unit rsyslog.service entered failed state.
2 Nov 30 15:31:43 iZuf6b1znamggglbunalhzZ systemd: rsyslog.service failed.
3 Nov 30 15:31:43 iZuf6b1znamggglbunalhzZ systemd: Stopped Dump dmesg to /var/log/dmesg.
4 Nov 30 15:31:43 iZuf6b1znamggglbunalhzZ systemd: Stopping Session 2 of user root.
5 Nov 30 15:31:43 iZuf6b1znamggglbunalhzZ systemd: Stopped target Timers.
如果文件太大了,一页显示不下,就要用到more命令,这个命令每次显示一页,按下空格键显示下一页,这个命令也有一些比较实用的使用技巧,例如想从第20行开始显示文件,可以用下面的命令
[root@iZuf6b1znamggglbunalhzZ ~]# more +20 /var/log/messages
Nov 30 15:31:43 iZuf6b1znamggglbunalhzZ systemd: Stopping Command Scheduler...
Nov 30 15:31:43 iZuf6b1znamggglbunalhzZ systemd: Stopping NTP client/server...
Nov 30 15:31:43 iZuf6b1znamggglbunalhzZ systemd: Stopping OpenSSH server daemon...
Nov 30 15:31:43 iZuf6b1znamggglbunalhzZ systemd: Stopping Job spooling tools...
显示文件开头几行用head命令,下面的命令显示文件开头的5行
[root@iZuf6b1znamggglbunalhzZ ~]# head -5 /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
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
显示末尾的几行用tail命令,这个命令除了显示末尾的几行文件外,用-f选项还可以持续跟踪文件的变化,比如下面的命令显示文件最后10行,当文件有新行加入时会显示新加入的行
[root@iZuf6b1znamggglbunalhzZ ~]# tail -f -n 10 /var/log/messages
Jul 15 14:53:33 iZuf6b1znamggglbunalhzZ systemd-logind: Removed session 44.
Jul 15 14:53:54 iZuf6b1znamggglbunalhzZ systemd: Started Session 45 of user root.
Jul 15 14:53:54 iZuf6b1znamggglbunalhzZ systemd-logind: New session 45 of user root.
Jul 15 14:53:54 iZuf6b1znamggglbunalhzZ systemd-logind: Removed session 45.
Jul 15 14:53:55 iZuf6b1znamggglbunalhzZ systemd: Started Session 46 of user root.
Jul 15 14:53:55 iZuf6b1znamggglbunalhzZ systemd-logind: New session 46 of user root.
Jul 15 14:53:55 iZuf6b1znamggglbunalhzZ systemd-logind: Removed session 46.
Jul 15 14:53:56 iZuf6b1znamggglbunalhzZ systemd: Started Session 47 of user root.
Jul 15 14:53:56 iZuf6b1znamggglbunalhzZ systemd-logind: New session 47 of user root.
Jul 15 14:53:56 iZuf6b1znamggglbunalhzZ systemd-logind: Removed session 47.
Jul 15 14:54:40 iZuf6b1znamggglbunalhzZ systemd: Started Session 48 of user root.
Jul 15 14:54:40 iZuf6b1znamggglbunalhzZ systemd-logind: New session 48 of user root.
Jul 15 14:54:40 iZuf6b1znamggglbunalhzZ systemd-logind: Removed session 48.
Jul 15 14:54:41 iZuf6b1znamggglbunalhzZ systemd: Started Session 49 of user root.
Jul 15 14:54:41 iZuf6b1znamggglbunalhzZ systemd-logind: New session 49 of user root.
Jul 15 14:54:41 iZuf6b1znamggglbunalhzZ systemd-logind: Removed session 49.
Jul 15 14:54:42 iZuf6b1znamggglbunalhzZ systemd: Started Session 50 of user root.
Jul 15 14:54:42 iZuf6b1znamggglbunalhzZ systemd-logind: New session 50 of user root.
Jul 15 14:54:42 iZuf6b1znamggglbunalhzZ systemd-logind: Removed session 50.
统计文本文件的行数、列数、字符数、字节数用wc命令
[root@iZ2ze0t8khaprrpfvmevjiZ ~]# wc /etc/passwd
33 70 1733 /etc/passwd
第一列33是文件的行数,第二列70是文件的单词数,单词是以空格为分隔符的,第三列1733是字符数或者字节数
单独查看行数用-l选项,单词数用-w选项,字符数用-m选项,字节数用-c选项,比如显示文件行数:
[root@iZuf6b1znamggglbunalhzZ ~]# wc -l /etc/passwd
21 /etc/passwd
用file命令可以看到文件的编码格式、文件的类型
[root@iZuf6b1znamggglbunalhzZ ~]# file /var/log/messages
/var/log/messages: UTF-8 Unicode text, with very long lines
2 grep
grep命令查找并显示字符所在的行,比如要想知道ssh服务监听的端口,可以查找ssh配置文件中Port所在的行,这里的P要大写
[root@iZuf6b1znamggglbunalhzZ ~]# grep Port /etc/ssh/ssh_config
# Port 22
Port所在的行默认是被注释掉的,此时,ssh使用的是默认的22端口,如果要知道Port在ssh配置文件的第几行,使用-n选项,
[root@iZuf6b1znamggglbunalhzZ ~]# grep -n Port /etc/ssh/ssh_config
41:# Port 22
grep 的-c选项显示所查找的字符串在文件中的行数
[root@iZuf6b1znamggglbunalhzZ ~]# grep -c localhost /etc/hosts
2
grep的-v选项用来排除字符所在的行,这个选项常用来在显示进程时排除grep本身,比如查看sshd进程信息
[root@iZuf6b1znamggglbunalhzZ ~]# ps -ef | grep sshd
root 1099 1 0 14:41 ? 00:00:00 /usr/sbin/sshd -D
root 1389 1099 0 14:42 ? 00:00:00 sshd: root@pts/0
root 2202 1408 0 15:00 pts/0 00:00:00 grep --color=auto sshd
[root@iZuf6b1znamggglbunalhzZ ~]# ps -ef | grep -v grep | grep sshd
root 1099 1 0 14:41 ? 00:00:00 /usr/sbin/sshd -D
root 1389 1099 0 14:42 ? 00:00:00 sshd: root@pts/0
使用了-v选项后,命令的输出不再显示grep进程,排除了grep进程的干扰,输出的结果更容易理解,看起来也更一致,在脚本编程时经常用到。
grep也提供-r选项,在目录及其子目录的所有文件中搜索特定字符串
[root@iZuf6b1znamggglbunalhzZ ~]# grep -r *.sh /etc
Binary file /etc/udev/hwdb.bin matches
/etc/NetworkManager/dispatcher.d/11-dhclient: for f in $ETCDIR/dhclient.d/*.sh; do
/etc/bashrc: for i in /etc/profile.d/*.sh; do
/etc/profile:for i in /etc/profile.d/*.sh /etc/profile.d/sh.local ; do
如果要搜索的字符串比较复杂,中间由空格或者特殊字符,就将其放到单引号内,单引号内也可以写正则表达式,如下面这个例子匹配ntp1...,ntp2...,....等,这列的单引号也
可以改成双引号,效果是一样的
[root@iZuf6b1znamggglbunalhzZ ~]# grep 'ntp[0-9].aliyun.com' /etc/ntp.conf
restrict ntp1.aliyun.com nomodify notrap nopeer noquery
restrict ntp2.aliyun.com nomodify notrap nopeer noquery
restrict ntp3.aliyun.com nomodify notrap nopeer noquery
restrict ntp4.aliyun.com nomodify notrap nopeer noquery
restrict ntp5.aliyun.com nomodify notrap nopeer noquery
restrict ntp6.aliyun.com nomodify notrap nopeer noquery
server ntp1.aliyun.com iburst minpoll 4 maxpoll 10
server ntp2.aliyun.com iburst minpoll 4 maxpoll 10
server ntp3.aliyun.com iburst minpoll 4 maxpoll 10
server ntp4.aliyun.com iburst minpoll 4 maxpoll 10
server ntp5.aliyun.com iburst minpoll 4 maxpoll 10
server ntp6.aliyun.com iburst minpoll 4 maxpoll 10
3 sed
sed是Linux系统中常用的流编辑器,sed这个名称是stream editor的缩写,这是一个面向行处理的工具,它以“行”为处理单位,针对每一行进行处理,处理后的结果会输出到标准输出,
这里用前面创建的test.txt文件来演示这个工具的几个用法,sed命令的格式是[address]action/argument/flags,地址用来选择操作的行,action是要做的操作,如新增、替换等,第三部分是操作的参数,不同的操作需要不同的参数,flags可以
表示操作的范围,比如经常可以看到的g参数,表示全部的意思,会对整行中所有匹配的内容进行操作。
[root@iZ2ze0t8khaprrpfvmevjiZ ~]# sed '3,5d' test.txt
test 1:this is test1
test 2:this is test1
test 6:this is test1
test 7:this is test1
test 8:this is test1
test 9:this is test1
test 10:this is test1
上面命令中d命令是删除的信息,sed删除了文件中3至5行,将其输出到标准输出,也可用$通配符,匹配至文件结尾
[root@iZ2ze0t8khaprrpfvmevjiZ ~]# sed '3,$d' test.txt
test 1:this is test1
test 2:this is test1
sed删除了第三行至文件结尾,只保留了前两行数据
a命令用来新增一行,下面的命令在文件的末尾增加一行,增加行的内容就是a后面的字符串。
[root@iZuf6b1znamggglbunalhzZ ~]# sed '$a admin:x:1000:1000:admin:/home/admin:/bin/bash' /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
adm:x:3:4:adm:/var/adm:/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
nscd:x:28:28:NSCD Daemon:/:/sbin/nologin
tcpdump:x:72:72::/:/sbin/nologin
admin:x:1000:1000:admin:/home/admin:/bin/bash
s命令用于在一行内做字符串替换,比如我们在安装linux操作系统后,根据安全的需要经常要做打开和关闭selinux,如果需要这个操作在系统重启后依然生效,需要编辑/etc/selinux/config文件,更改selinux值,最简单的办法是用vi打开这个文件,编辑一下存盘,高效一点的办法是用sed的s命令给,查找到配置问价中selinux的行,将disabled值替换为enforing,用-i选项可以直接编辑文件。
[root@iZuf6b1znamggglbunalhzZ ~]# sed 's/SELINUX=disabled/SELINUX=enforcing/' /etc/selinux/config
# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
# enforcing - SELinux security policy is enforced.
# permissive - SELinux prints warnings instead of enforcing.
# disabled - No SELinux policy is loaded.
SELINUX=enforcing
# SELINUXTYPE= can take one of three values:
# targeted - Targeted processes are protected,
# minimum - Modification of targeted policy. Only selected processes are protected.
# mls - Multi Level Security protection.
SELINUXTYPE=targeted
c操作用于改变一行的内容,比如下面的命令将改变了第一行的内容,c 后面的字符串是改变后的内容
[root@iZuf6b1znamggglbunalhzZ ~]# sed '1c abcdefg' /etc/passwd
abcdefg
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
nscd:x:28:28:NSCD Daemon:/:/sbin/nologin
tcpdump:x:72:72::/:/sbin/nologin
4 AWK
AWK 是一种Linux中处理文本文件的语言,具有强大的文本分析功能,它的名字来源于三位创始人 Alfred Aho,Peter Weinberger, 和 Brian Kernighan ,分别取了三位创始人的姓的首字符,和grep、sed一起被称为linux中三剑客之,三剑客之首就是 AWK。
awk经常用来打印文本中的特定列,比如我们在shell编程时经常需要获得某一网络接口的ip地址,先用ifconfig命令看一下网络接口信息
[root@iZ2ze0t8khaprrpfvmevjiZ ~]# ifconfig lo
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 103285 bytes 6961676 (6.6 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 103285 bytes 6961676 (6.6 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
用awk获取接口的ip地址,awk的命令一般卸载单引号内,最简单的命令向下面这样,第一部分是匹配模式,用来查找要操作的行,第二部分是{}内是要执行的操作,这里是打印第二列,$n是AWK的内置变量,$0表示所有列,其它的表示第n列。
[root@iZ2ze0t8khaprrpfvmevjiZ ~]# ifconfig lo|awk '/inet 1/{print $2}'
127.0.0.1
在linux文件系统中,root(/)文件系统是非常重要的,root文件系统满了,会造成操作系统和软件故障,使用下面的命令可以查看linux root文件系统的剩余空间
[root@iZ2ze0t8khaprrpfvmevjiZ ~]# df -h |awk '/\/$/{print $4}'
22G
上面的awk命令中,匹配模式是/\/$/,$配置一行的结尾,\为转义符,取消后面紧跟的/的特殊含义,这个配置模式的意思就是匹配以\结尾的行,看一下df -h的输出,有利于我们理解这个匹配模式,
[root@iZ2ze0t8khaprrpfvmevjiZ ~]# df -h
Filesystem Size Used Avail Use% Mounted on
devtmpfs 891M 0 891M 0% /dev
tmpfs 909M 476M 433M 53% /dev/shm
tmpfs 909M 484K 908M 1% /run
tmpfs 909M 0 909M 0% /sys/fs/cgroup
/dev/vda3 40G 19G 22G 47% /
/dev/vda2 100M 7.3M 93M 8% /boot/efi
tmpfs 182M 0 182M 0% /run/user/0
在df -h的输出中,只有root文件系统是以’/’结尾的,匹配到之后,打印第四行及时就是root文件系统的剩余空间,如果要显示结果更友好一点,也可以拼接一下字符串
[root@iZ2ze0t8khaprrpfvmevjiZ ~]# df -h |awk '/\/$/{print "root filesystem left space is "$4}'
root filesystem left space is 22G
有的企业一般要求在linux系统中,自定义用户的id要大于1000,在这种情况下用户id<1000的基本都是系统内置用户,如何查询系统中的内置用户,用下面的命令
[root@iZuf6b1znamggglbunalhzZ ~]# awk -F: '$3<1000{x++} END{print x}' /etc/passwd
21
上面的命令中,-F设置分隔符,在这里我们不使用默认的空格作为分隔符,而是使用“:”作为分隔符,文件的第三列是用户id,只要第三列的值小于1000,x(起始值为0)就加一,文件扫描结束时,打印x值,就是文件中所有用户id小于1000的用户的数量。
我们创建linux用户时,经常不需要用户由执行shell命令的权限,把用户的shell只是为nologin,比如mysql用户,这样可以提高安全性,怎样取出系统中有执行命令权限的用户,用下面的命令:
[root@iZuf6b1znamggglbunalhzZ ~]# awk -F: '$7!~/nologin$/{print $1,$7}' /etc/passwd
root /bin/bash
sync /bin/sync
shutdown /sbin/shutdown
halt /sbin/halt
同样要设置分隔符为“:”,,只要第七列不以“nologin”结尾,我们就打印第一列和第7列。
下面这个例子没有什么实用价值,只是演示一下awk的格式化输出和文本文件分析能里,我们打印出/etc/password的前三行的名字和uid,并且打印出行数
[root@iZuf6b1znamggglbunalhzZ ~]# head -3 /etc/passwd | awk 'BEGIN{FS=":";print "name\tuid"}{print $1,"\t"$3}END{print "sum lines "NR}'
name uid
root 0
bin 1
daemon 2
sum lines 3
命令用到awk的begin、end结构,begin后面紧跟的处理开始的动作,在这里,我们打印出列头name和uid,\t是tab键,后面的动作应用到文本处理过程中,打印出第1列和第三列,这两列之间也用tab键分隔,文本处理结束后进行的操作是打印一个汇总行,NR是AWK内置变量,表示处理的行数。
一台linux服务器,如果我们想知道它上面处于不同状态的tcp的数量怎么做,如果不用脚本,也可以手工处理,运行一下netstat -na命令,看一下tcp连接的状态,统计一下每种状态下连接的数量,这个需求也用下面的脚本也可以实现
[root@iZuf6b1znamggglbunalhzZ ~]# netstat -na | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
LISTEN 1
ESTABLISHED 2
TIME_WAIT 1
这个脚本有几个awk中比较高级的用法,需要解释一下,命令中的匹配模式是/^tcp/ ,即匹配以tcp开头的行,$NF是AWK的内置变量,表示行的最后一列,看一下netstat -na中以tcp开头的行最后一列是什么
[root@iZ2ze0t8khaprrpfvmevjiZ ~]# netstat -na|grep tcp
tcp 0 0 0.0.0.0:111 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
tcp 0 64 172.20.11.244:22 112.224.4.86:47071 ESTABLISHED
tcp 0 0 172.20.11.244:56566 100.100.30.26:80 ESTABLISHED
tcp 0 0 172.20.11.244:60892 100.100.18.120:443 TIME_WAIT
可以看到,最后一列正是连接的状态,S[$NF]定义一个数组,这个数组的元素是S[LISTEN], S[ESTABLISHED],数组元素的初始值是0,在文本的处理过程中,如果匹配到行,就将数组元素S[连接状态]的值加1,整个文本处理完后,输出数组内的每一个元素及其值。
awk和其它脚本命令组合起来,看一实现一些比较复杂的操作,比如杀掉一组进程
[root@iZuf6b1znamggglbunalhzZ ~]# ps -ef | grep httpd | awk {'print $2'} | xargs kill -9