现下,多数生产系统的数据库都运行在linux操作系统下,熟练使用liunx各种工具有助于提高工作效率,本文记录了我在工作中使用的linux文本工具小技巧,供各位墨友参考。
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
这里的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
2 文本显示技巧
显示行号
linux下最常用的文本显示工具是cat和more,这两个工具使用比较简单,但也有一些平时不为人注意的选项,比如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.
从第n页开始分页显示
如果文件太大了,一页显示不下,就要用到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.
统计文本文件的行数、列数、字符数、字节数用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
3 文本查找工具
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选项,在目录及其子目录的所有文件中搜索特定字符串
```bash
[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-4].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
4 文本编辑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
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
5 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列。
```bash
[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
设置列分隔符
awk的默认列分隔符是空格,也个可以设置为别的分隔符。例如,有的企业一般要求在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内置变量,表示处理的行数。
进阶用法-数组的使用
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
6 一个有用的脚本
下面这个脚本用awk语言编写,可以用来分析oracle osw 的iostat日志,显示IO等待时间超过特定值的时间和条目
echo time await r_await w_await
awk '{
if (/([0-9]{2}):([0-9]{2}):([0-9]{2})/ )
{
while ((getline tmp) > 0 )
if (tmp !~ /([0-9]{2}):([0-9]{2}):([0-9]{2})/) {
split(tmp,cur_line)
if (cur_line[12] > 10 && cur_line[12] ~ /[0-9]+/ ) {
print $3,$4,$5,tmp
}
} else {
break
}
}
}' * | awk '$13 > 4 && $5 !~ /\// {print $1,$2,$3,$4," ",$13," ",$14," ",$15}'
将上面的内容保存到一个shell脚本中,放到OSW安装目录archive/oswiostat目录下,命令的输出如下
time device await r_await w_await Jul 26 15:32:49 sda 11.00 0.00 11.00 Jul 26 15:32:49 dm-0 11.00 0.00 11.00 Jul 26 16:39:57 dm-0 15.50 0.00 15.50




