5: 文本处理工具

1. 文本编辑工具vim

1.1 vim介绍

在Linux中我们经常编辑修改文本文件, 即由ASCII, Unicode或其他编码的纯文字的文件. Vim是一款使用最多的Linux平台的文本编辑工具

vim安装:

# 最小化安装的系统, 需要单独安装vim包

[root@demo-c8 ~]# rpm -ql vim-enhanced
/etc/profile.d/vim.csh
/etc/profile.d/vim.sh
/usr/bin/rvim
/usr/bin/vim
/usr/bin/vimdiff
/usr/bin/vimtutor
/usr/lib/.build-id
/usr/lib/.build-id/7f
/usr/lib/.build-id/7f/37d6ce6c2273cc7bdf383618236c268dbeb092

1.2 使用 vim 初步

1.2.1 vim 命令格式

vim [OPTION]... FILE...

常用选项:

vim打开文件, 光标默认处在第一行行首
+#  打开文件后,让光标处于第#行的行首,`vim + FILE`: 打开文件后, 光标处于最后一行行首. 
+/PATTERN   让光标处于第一个被PATTERN匹配到的行的行首
-b file 二进制方式打开文件
-d file1 file2...  比较多个文件,相当于 vimdiff
-m file    只读打开文件
-e file    直接进入ex模式,相当于执行ex  file 
-y file    Easy mode (like "evim", modeless),直接可以操作文件,ctrl+o:wq|q! 保存和不保存退出

说明:

  • 如果该文件存在,文件被打开并显示内容
  • 如果该文件不存在,当编辑后第一次存盘时创建它

1.2.2 三种主要模式和转换

vim 是一个模式编辑器,其行为是依赖于 vim的模式

三种常见模式:

  • 命令或普通(Normal)模式:默认模式,可以实现移动光标,剪切/粘贴文本
  • 插入(Insert)或编辑模式:用于修改文本
  • 扩展命令(extended command )或命令(末)行模式:保存,退出等

模式转换

  • 命令模式 --> 插入模式
i      insert, 在光标所在处输入
I      在当前光标所在行的行首输入
a      在当前光标所在处后面输入
A      在当前光标所在行行尾输入
o      在当前光标所在行的下方打开一个新行
O      在当前光标所在行的上方打开一个新行
行首插入: I
行尾插入: A
上一行插入: O
下一行插入: o
光标处插入: i
光标处下一位插入: a
  • 插入模式 -- ESC -- 命令模式
  • 命令模式 -- : -- 扩展命令模式
  • 扩展命令模式 -- ESC -- 命令模式

1.3 扩展命令模式

按冒号 " : " 可以进入Ex模式,创建一个命令提示符: 处于底部的屏幕左侧

1.3.1 扩展命令模式基本命令

w                           写(存)磁盘文件
wq                          写入并退出
x                           写入并退出
X                           加密
q                           退出
q!                         不存盘退出,未保存更改都将丢失
r   filename                读取文件内容到当前文件中, 在光标所在行下一行插入
范例: :r/data/prac/test.txt, 如果读取的是和当前文件在同一个目录的文件, 要使用./文件名

w   filename                将当前文件内容写入另一个文件
范例: :w/data/prac/test.txt, 如果写入的是和当前文件在同一个目录的文件, 要使用./文件名. 如果目标文件不存在, 会自动创建文件, 并写入内容
                             如果目标文件存在, 那么就要加!,去覆盖掉原文件内容, :w!./f1.txt

!command                    执行命令, 打印在屏幕上,但是不会追加到文件中
r!command                   读取命令的输出. 将命令的输出追加到鼠标当前行的下一行

1.3.2 地址定界

在末行模式执行

格式:

地址界定后需要接命令, 来完成操作
:start_pos,end_pos CMD

1.3.2.1 地址定界格式

在末行模式输入以下格式

1. #          将光标移动到第几行的行首, :2就是移动到第二行行首
2. .          将光标移动到当前行的行首
3. $          将光标移动到最后一行行首, %也是移动到最后一行行首
4. $-#        将光标移动到倒数第#+1行, $-1就是倒数第二行; 因为倒数第一行是$, $-1就是倒数第二行
5. #,#        选定范围,从第#起, 到第#行止; 2,5就是第二行到第五行;配合后续命令使用,
比如, 删除从第2行到第5行的数据就是, :2,5d
      :10,20y,就是复制从第10行到第20行数据
      复制后可以移动光标到某一行,然后输入p键, 则把复制内容粘贴到该行的下一行. 
      即使粘贴时, 光标不在行首也没关系, 因为会复制到下一行,而不是从光标当前位置开始插入

6. #,+#       从第#行开始起, 向下取#行, 2,+3 就是从第二行开始向下取3行, 也就是第2到5行
7. .,$-1      从当前行到倒数第二行; .,$-#, 从当前行到倒数第#+1行
8. %          表示全文, 相当于 1,$ 

1.3.2.2 地址定界后跟一个编辑命令

d           #删除, 相当于剪切
y           #复制
w file      #将范围内的行另存至指定文件中  1,2w /opt/passwd.txt
r file     #在指定行的下一行插入指定文件中的所有内容 1r /opt/passwd.txt

1.3.3 查找并替换

格式:

搜索范围s/要查找的内容/替换为的内容/修饰符

说明:

要查找的内容: 可使用基本正则表达式模式
替换为的内容: 不能使用模式, 但可以使用\1, \2, ...等后向引用符号; 还可以使用"&"引用前面查找时查找到的整个内容

范例: 搜索/etc/password中的root账号, 替换为admin

  1. 不加修饰符, 默认情况会查找范围内全部匹配到的数据, 但是每一行只会替换第一个匹配到的字符
:%s/root/admin/    # %为全文搜索
  1. 通过修饰符g, 替换范围内全部匹配到的数据
:%s/root/admin/g
  1. 通过修饰符i, 定义搜索时不区分大小写, 默认搜索是区分大小的.
:%s/admin/ROOT/ig

注意: 搜索是可以区分或者不区分大小写, 但是替换的内容一定是区分大小的, 替换成ADMIN就是改成ADMIN

查找替换中的分隔符/可以替换为其他字符, @,#

范例:

s@@@
s###

1.3.4 定制vim的工作特性

扩展命令模式的配置只是对当前vim进程有效, 可将配置存放在文件中持久保存

配置文件:

/etc/vimrc 全局
~/.vimrc  个人

针对vim正在打开的文件临时生效:

范例: 用4个空格表示tab

切换到末行模式, 针对某个脚本设置
:set expandtab
:set 4

注意: 一旦关闭文件后, 临时的配置就会失效, 下次打开文件后, 需要再次设置

9. :set nu    显示行号
10. :set nonu  不显示行号
11. :set nohl   不高亮
12. 命令(普通)模式直接输入/, 进入搜索模式, 可以搜索关键字

1.3.4.1 行号

显示行号: set no
取消显示: set nonu

1.3.4.2 忽略字符的大小写

启用: set ic
不忽略: set noic

1.3.4.3 自动缩进

启用: set ai, 输入回车后, 下一行和上一行行首对齐
禁用: set noai

1.3.4.4 复制保留格式

启用: set paste, 使用了set ai后, 防止粘贴文本时串行, 出现格式混乱
禁用: set nopaste

1.3.4.5 显示Tab^|和换行符$

启用: set list
禁用: set nolist

1.3.4.6 高亮搜索

启用: set hls
禁用: set nohl

1.3.4.7 语法高亮

启用: syn on
禁用: syn off

1.3.4.8 文件格式

启用Windows格式: set fileformat=dos
启用Unix格式; set fileformat=unix
简写 set ff=dos|unix, 将文本格式改为Windows/Unix

1.3.4.9 Tab用空格代替

不同的远程工具下, tab和空格数量的对应关系不同
启用: set expandtab 默认为8个空格代替Tab
禁用: set noexpandtab

1.3.4.10 Tab用指定空格的个数代替

启用: set tabstop=# 指定#个空格代替Tab
简写: set ts=4

1.3.4.11 设置光标所在行的标识线

启用: set cul
禁用: set nocursorline

1.3.4.12 帮助

set 帮助

:help option-list
:set or :set all

1.4 命令模式(普通模式)

行首行尾跳转

^: 跳转至行首的第一个非空白字符
0: 跳转至行首
$: 跳转至行尾

行间移动

# 扩展命令模式下: :行编号, :1表示第一行 :%最后一行
# 普通命令模式下: 行编号G, 1G或者gg表示第一行, G表示最后一行

替换命令

r: 只替换光标所在处的一个字符
R: 切换到REPLACE模式, 在末行会出现REPLACE提示, 按ESC回到命令模式

删除命令

d: 删除命令, 可结合光标跳转字符, 实现范围删除
d$: 删除光标当前到行尾, 或者用D
d^: 删除光标当前到非空行首
d0: 删除光标当前到行首
dd: 剪切光标所在行, 之后可以移动到目标处用p粘贴到光标下一行
数字dd: 删除从当前行开始的多行, 2dd表示从当前行开始, 删除两行, 包括当前行
dG: 从光标所在行开始往后, 删除整个文本
dgg: 从光标所在行开始往前, 删除整个文件 

删除当前行尾的换行符

# 也就是把下面一行和当前行合并, 将光标移动到上面一行, 然后敲J
J

大小写转换

~

复制和粘贴

y: 复制
yy: 复制当前行, 相当于Y
y$: 从光标处复制到行尾
y0: 从光标处复制到行首
y^: 从光标处复制到非空行首
数字yy: 从当前行开始复制多行
P: 将复制的内容粘贴到光标所在行的上面
p: 将复制的内容粘贴到光标所在行的下面

查找

/模式: 从当前光标所在处向文本末尾查找
?模式: 从当前光标所在处向文本首部查找
n: 与命令同方向
N: 与命令反方向

撤销

u: 撤销最近的更改
数字u: 撤销之前几次更改
U: 撤销光标所在行此行的所有更改
ctrl+r: 重做最后一次撤销的更改

高级用法

  • <起始位置><命令><结束为止>

常见命令: y复制, d删除, gU变大写, gu变小写

范例: 复制一行内容

0y$ 
0: 先定位到行首
y: 从行首开始赋值
$: 拷贝到本行的最后一个字符

范例: 粘贴"admin"100次

100iadmin[ESC]

命令模式执行

敲100, 表示粘贴100次
敲i, 进入插入模式
敲admin, 输入要粘贴的内容
敲ESC退出插入模式, 回到普通模式
  • 针对一组特殊符号内的内容进行操作

范例: 删除一组特殊符号内的内容

di[

命令模式执行, 并且要将光标先移动到这组特殊符合内

d: 执行删除
i: 
[: 表示删除的是一组[]内的全部内容
yi(
di"
di'
dtx: 从当前光标位开始删除, 直到遇到第一个字符x
ytx: 从当前光标位开始复制, 直到遇到第一个字符x

1.5 可视化模式

  • 通过键盘光标选中要修改的字符/行或者矩形块, 然后进行内容操作
v: 面向字符, 在末行显示 -- VISUAL --, 可以按照字符进行选择, 然后执行命令, 比如删除或者复制
V: 面向整行, 在末行显示 -- VISUAL LINE --, 按照一整行去选择, 然后执行命令, 比如删除或者复制
ctrl+v: 面向块, 按照一个矩形块去选择, 在末行显示 --  VISUAL BLOCK --

范例: 在指定的列插入相同的内容

1. 将光标移动到要操作的行
2. ctrl+v, 进入可视化模式, 选择要操作的列和行
3. 输入I
4. 输入要插入的内容
5. 按ESC键

案例1: 在整个文件的行首, 插入#

gg, 先将光标移动到文件首行
ctrl+v, 进入块可视化模式
输入G, 这样可以选中每一行的第一个字符
输入I, 切换至插入模式, 这样可以在每一行的行首插入字符
输入#
ESC退出可视化模式

案例2: 删除每一行的第一个字符

gg, 先将光标移动到文件首行
ctrl+v
G
x
ESC

案例3: 在指定的列插入相同的内容

原理和插入#一样
ctrl+v
移动光标选中需要插入信息的列
输入I
输入内容
ESC

案例4: 复制/etc/rc.d/init.d/functions文件至/tmp目录. 替换/tmp/functions文件中的/etc/sysconfig/init为/var/log

:%s#/etc/sysconfig/init#/var/log#

案例5: 删除/tmp/functions文件中所有以#开头, 且#后面至少有一个空白字符的行的行首的#号

:%s@^#\( \+.*\)@\1@ # vim末行模式的搜索替换只支持基本正则表达式

2 文本常见处理工具

2.1 文本内容查看命令

2.1.1 查看文本文本内容

2.1.1.1 cat

cat 只能看文本文件, cat文件之前, 可以先通过file命令查看文本格式, 确定是否可以cat查看

[root@demo-c8 ~]# file /dev/urandom 
/dev/urandom: character special (1/9)
[root@demo-c8 ~]# file /etc/fstab 
/etc/fstab: ASCII text

格式:

cat [OPTION]... [FILE]...

常见选项:

-E 显示行结束符$
-A 显示所有控制符
-n 对显示出的每一行进行编号
-b 仅对非空行显示行号, 等于`nl`命令
-s 压缩连续的空行成一行

范例: cat -A查看Linux格式文件

# 准备测试文件

[root@demo-c8 ~]# cd /data
[root@demo-c8 data]# ls
[root@demo-c8 data]# vim f1.txt
a   b
cc
d i v
  • cat -A: $:Linux的换行符


    image.png
[root@demo-c8 data]# hexdump -C f1.txt   # $符号就是0a换行
00000000  61 20 20 20 62 0a 63 63  0a 64 20 69 20 76 20 0a  |a   b.cc.d i v .|
00000010

范例: cat -A查看Windows格式文件

image.png
  • cat -A: . ^M: Windows格式的回车符号, 也就是0d
image.png
[root@demo-c8 data]# hexdump -C a.txt 
00000000  61 20 20 31 0d 0a 62 20  20 32 0d 0a 63 20 20 33  |a  1..b  2..c  3|
00000010

范例: cat多行重定向生成配置文件

cat > FILE_NAME <
>
EOF
  • reset命令

恢复终端环境, 比如用cat打开了一些非文本文件后, 可能会执行一些乱码. 这时可能出现cat其他文本文件也是乱码的情况, 这时用reset命令恢复终端环境. 如果还不行, 可以断开SSH连接, 或者重启. 重启再不行,就排错吧. 所以不要用cat命令随便打开文件.

  • tac命令
反向显示文本内容, 把第一行显示在最后一行, 和cat正好相反
  • rev命令
反向显示文本内容, 把第一列显示在最后一列, 和cat正好相反

2.1.2 查看非文本文件内容

2.1.2.1 hexdump

  • hexdump命令

有些文件是非文本文件, 可以用hexdump查看, 并且以指定的进制显示

格式:

hexdump [options] ...
Display file contents in hexadecimal, decimal, octal, or ascii.

一般用-C选项以16进制显示, 比如hexdump -C -n 512 /dev/sda, 查看sda硬盘前512字节

硬盘的前512个字节是非文本内容

image.png

范例: 将文本字符以ASCII码16进制显示

[root@demo-c8 ~]# echo abcd | hexdump -C 
00000000  61 62 63 64 0a                                    |abcd.|
00000005

2.2 分页查看文件内容

只要是支持标准输入的命令都可以用管道, 将前面命令的结果传给自己

more FILE

回车, 下一行
空格, 下一页
ctrl+d: 往回翻
q: 退出查看

缺点: 翻到了最后一页就自动退出, 不能再往回翻

less FILE

q: 退出查看
支持page up | page down翻页 
翻到了最后一页不会自动退出
输入/可以搜索, n跳到下一个匹配, N跳到上一个匹配, 和vim中的搜索用法相同

2.3 显示文本前或后n行内容

head命令

默认显示文本前10行
-n数字 或者 -数字: 显示文本的前几行
-C数字: 显示文本的前几个字节

范例: head显示前n行

[root@demo-c8 ~]# seq 100 > text.txt
[root@demo-c8 ~]# head text.txt 
1
2
3
4
5
6
7
8
9
10

范例: head显示前n个字节

# 数字和换行符各占一个字节
[root@demo-c8 ~]# head -c 10 text.txt 
1 # 1和换行符
2
3
4
5

tr命令

-d 删除指定内容
-s 压缩, 将连续的指定内容压缩成一个字符
-c 取反, -dc就是除了后面匹配的内容, 都删除, 可以接通配符

面试题: 生成字符+数字随机密码

利用/dev/urandom文件, 该文件是字符块文件,生成随机信息, 不能用cat直接查看显示在屏幕上, 但是可以将cat结果通过管道传给tr命令, 然后把除了字符和数字的其他字符乱码都删除.这样就保留了随机的字符和数字

# /dev/random和/dev/urandom都是随机字符设备
0O8xmS]NKN[12:44:45 root@centos8-3 ~]#cat /dev/urandom | tr -dc '[:alnum:]' | head -c 10
mteifbL6l9[12:44:46 root@centos8-3 ~]#cat /dev/random | tr -dc '[:alnum:]' | head -c 10
GspCOBi05R[12:44:47 root@centos8-3 ~]#

tail命令

范例: 显示ifconfig命令的第二行

[root@demo-c8 ~]# ifconfig | head -n2 | tail -1
        inet 10.0.0.108  netmask 255.255.255.0  broadcast 10.0.0.255
tail -f: 跟踪文件变化, 常用于跟踪日志跟踪
tail -f: 默认显示现有日志的最后十行, 从倒数第十行开始, 显示到最新一行, 并且持续追踪新发生的日志, 新发生的日志会追加显示
-f: 追踪文件描述符, fd, 即使文件被删除, 也会持续追踪, 因为文件被删除后, 文件描述符不会被删除
-F: 追踪文件名称, 当文件被删除后, 追踪停止, 如果新建了一个同名文件, 那么会重新追踪

2.4 按列抽取文本cut

cut命令

当分隔符连续出现时, 比如df命令的结果, 如果用cut指定分隔符为空格时, 连续的空格也会被算作一列, 此时要用tr -s先压缩空格

格式:

cut [option]... [FILE]...

选项:

-d DELIMITER: 指明分隔符,默认tab
-f FIElDS:
     #: 第#个字段,例如:3, 表示仅取第三个字段
     #,#[,#]:离散的多个字段,例如:1,3,6
     #-#:连续的多个字段, 例如:1-6
     混合使用:1-3,7
-c 按字符切割显示
--output-delimiter=STRING指定输出分隔符, 比如按:为分隔符切割, 按照;为分隔符显示
[root@demo-c8 ~]# cut -d: -f1 /etc/passwd
root
bin
daemon
adm
lp
sync
shutdown
halt
mail
operator
games
ftp
nobody
dbus
systemd-coredump
systemd-resolve
tss
polkitd
geoclue
rtkit
...
[root@demo-c8 ~]# cut -d: -f1,3 /etc/passwd
root:0
bin:1
daemon:2
adm:3
lp:4
sync:5
shutdown:6
halt:7
mail:8
operator:11
games:12
ftp:14
...
[root@demo-c8 ~]# cut -d: --output-delimiter=";" -f1,3 /etc/passwd
root;0
bin;1
daemon;2
adm;3
lp;4
sync;5
shutdown;6
halt;7
mail;8
operator;11
games;12
...

范例: 显示磁盘使用率, 按由大到小显示

[root@demo-c8 ~]# df
Filesystem     1K-blocks    Used Available Use% Mounted on
devtmpfs         3957252       0   3957252   0% /dev
tmpfs            3985420       0   3985420   0% /dev/shm
tmpfs            3985420    9832   3975588   1% /run
tmpfs            3985420       0   3985420   0% /sys/fs/cgroup
/dev/sda2       41922560 4542680  37379880  11% /
/dev/sda5       41922560  325336  41597224   1% /data
/dev/sda1         999320  192552    737956  21% /boot
tmpfs             797084    1168    795916   1% /run/user/42
tmpfs             797084       4    797080   1% /run/user/0
[root@demo-c8 ~]# df | tr -s " " | cut -d " " -f1,5 | tac | sort -k2 -r
Filesystem Use%
/dev/sda1 21%
/dev/sda2 11%
tmpfs 1%
tmpfs 1%
tmpfs 1%
/dev/sda5 1%
tmpfs 0%
tmpfs 0%
devtmpfs 0%

范例: 取本机ip地址

[root@demo-c8 ~]# ifconfig
ens160: flags=4163  mtu 1500
        inet 10.0.0.108  netmask 255.255.255.0  broadcast 10.0.0.255
        inet6 fe80::20c:29ff:fe97:37c8  prefixlen 64  scopeid 0x20
        ether 00:0c:29:97:37:c8  txqueuelen 1000  (Ethernet)
        RX packets 45571  bytes 31757064 (30.2 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 31525  bytes 3744162 (3.5 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 48  bytes 4080 (3.9 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 48  bytes 4080 (3.9 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

virbr0: flags=4099  mtu 1500
        inet 192.168.122.1  netmask 255.255.255.0  broadcast 192.168.122.255
        ether 52:54:00:86:db:73  txqueuelen 1000  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
[root@demo-c8 ~]# ifconfig | head -2 | tail -1 
        inet 10.0.0.108  netmask 255.255.255.0  broadcast 10.0.0.255
[root@demo-c8 ~]# ifconfig | head -2 | tail -1  | tr -s " " | cut -d" " -f3
10.0.0.108

2.5 合并多个文本paste

paste合并多个文件里相同行号的列到同一行

格式:

paste [OPTION]... [FILE]...

常用选项:

-d 分隔符: 指定分隔符, 默认为tab
-s: 所有行合成一行显示, 默认分隔符为tab

范例: 合并a.txt和b.txt

[root@demo-c8 ~]# vim a.txt
a
b
c

[root@demo-c8 ~]# vim b.txt
1
2
3
image.png
image.png
image.png
image.png

paste: 矩阵转置, 将文件的列转为行, 默认分隔符为tab

image.png

ls显示目录内文件时, 虽然是横向显示, 但是实际是纵向显示每个文件的. 也可用ls -1来查看

[13:06:59 root@centos8-3 ~]#ls
anaconda-ks.cfg  a.txt  b.txt
[13:07:01 root@centos8-3 ~]#ls -1
anaconda-ks.cfg
a.txt
b.txt

2.6 分析文本的工具

2.6.1 收集文本统计数据wc

wc命令可以用来统计文件的行总数, 单词总数, 字节总数和字符总数

可以对文件或者STDIN标准输入中的数据进行统计

常用选项:

-l   只统计行数
-w   只统计单词总数. wc统计文本单词个数, 是以空格来区分单词的
-c   只统计字节总数
-m   只统计字符总数
-L   显示文件中最长行的长度

范例: 可以用ls | wc -l. 判断目录里有几个文件. 如果需要统计隐藏文件就用ls -a

[13:07:46 root@centos8-3 ~]#ls
anaconda-ks.cfg  a.txt  b.txt
[13:07:49 root@centos8-3 ~]#ls | wc -l
3

范例: wc -L: 显示文本中, 最长一行的字符数

[root@demo-c8 ~]# cat /etc/passwd
tss:x:59:59:Account used by the trousers package to sandbox the tcsd daemon:/dev/null:/sbin/nologin
[root@demo-c8 ~]# wc -L /etc/passwd
99 /etc/passwd

范例: wc FILE

[root@demo-c8 ~]# wc /etc/passwd
  52            120               2901      /etc/passwd
文本行数   文本单词数   文本字节数

[root@demo-c8 ~]# ll /etc/passwd
-rw-r--r--. 1 root root 2901 Sep  5 15:45 /etc/passwd

2.6.2 文本排序sort

sort把整理过的文本显示在标准输出上, 并不改变原始文件

格式:

sort [OPTIONS] FILE(s)

常用选项:

-r 执行反方向(由上至下)整理
-R 随机排序
-n 执行按数字大小整理
-f 忽略(fold)字符串中的字符大小写
-u 选项(独特,unique),合并重复项,即去重
-t c 使用c做为字段界定符, 也就是指定分隔符, 默认按照空格分隔
-k # 按照第几列来排序

范例: 取出uid最大的前三行, 只显示用户名和uid

[root@demo-c8 ~]# cp /etc/passwd .
[root@demo-c8 ~]# cut -d: -f1,3 passwd | sort -t: -k2 -nr | head -3
nobody:65534
heiheiheihei:1004
heiheihei:1003

范例: 统计一共有多少个主机ip访问了nginx服务器

cut -d" " -f1 /var/log/nginx/access_log | sort -u | wc -l

范例: 统计每个ip访问了多少次

# 第一个sort是为了把所有的ip地址, 按照顺序进行排序, 这样相同的ip就会连续出现, 便于uniq做去重, 因为uniq只有在相邻的两行是相同的内容时才会去重
# uniq -c, 对ip地址进行去重, 并且显示每个ip地址出现的次数
# sort -k1 -nr, 按照第一列, 也就是相同ip出现的次数排序, 并且按照数字大小, 从大到小排序
[root@demo-c8 ~]# cut -d" " -f1 access_log  | sort | uniq -c | sort -k1 -nr
   4870 172.20.116.228
   3429 172.20.116.208
   2834 172.20.0.222
   2613 172.20.112.14
   2267 172.20.0.227
   2262 172.20.116.179
   2259 172.20.65.65

范例: 按照/etc/passwd中的uid字段把文本进行排序

[13:13:46 root@centos8-3 /data/prac]#sort -t: -k 3 -n /etc/passwd
-t:  指定分隔符为冒号, 指定第几列, 要定义分隔符
-k 数字: 指定第几列
-n: 如果指定的列都是数字, 想要按照数字大小排序, 需要-n, 默认是按照ASCII码顺序, 从左到右,012...9AaBb...Zz, 从左到右比较每一位

范例: 对用户名和uid,按照uid大小排序

[13:20:31 root@centos8-3 /data/prac]#cut -d: -f1,3 /etc/passwd | sort -t: -k 2 -n 
[13:48:59 root@centos8-3 /data/prac]#cut -d' ' -f1 access_log | sort -u | wc -l
201

sort -u: 去重
sort 默认就是从左到右, ASCII码顺序排序, 比较每一位, 012...9AaBb...Zz

2.6.3 去重uniq

如果相邻的两行是相同的, 那么uniq才会去重, 所以uniq只会对相邻的两行, 并且两行内容相同的情况下, 才会去重

uniq -c 显示重复的个数, 在每行显示

[13:52:09 root@centos8-3 /data/prac]#cut -d' ' -f1 access_log | sort | uniq -c | sort -nr  | head -1
   4870 172.20.116.228

uniq -d 只显示相邻的重复的数据
uniq -u 只显示没有相邻重复的

范例: lastb命令查看日志, 并且统计

  • lastb显示失败的登录记录, 包含ip等
[14:08:31 root@centos8-3 /data/prac]#lastb -f btmp-34 | tr -s ' ' |  cut -d ' ' -f3 | sort | uniq -c | sort -nr | head -10
  86294 58.218.92.37
  43148 58.218.92.26
  18036 112.85.42.201
  10501 111.26.195.101
  10501 111.231.235.49
  10501 111.204.186.207
  10501 111.11.29.199
  10499 118.26.23.225
   6288 42.7.26.142
   4236 58.218.92.30

面试题: 取两个文件, 相同和不同的行? 两个文件, 对应的行, 哪些是相同的哪些是不同的

先通过cat打开两个文件, 然后用sort排序, 默认按照ASCII码顺序, 把相同的行排列到相邻的位置, 再用uniq去重, -d会显示相同的行, -u显示不相同的行

cat FILE1 FILE2 | sort | uniq -d
cat FILE1 FILE2 | sort | uniq -u
[root@demo-c8 ~]# cat a.txt 
a
b
1
2
c

[root@demo-c8 ~]# cat b.txt 
1
2
3
# 相同的行

[root@demo-c8 ~]# cat a.txt b.txt | sort | uniq -d 
1
2
# 不同的行

[root@demo-c8 ~]# cat a.txt b.txt | sort | uniq -u
3
a
b
c

2.6.4 比较文件

2.6.4.1 diff

diff命令可用于比较两个文件之间的区别, diff命令的输出可被保存在一种叫做补丁的文件中

常用选项:

diff FILE1 FILE2 
-u 详细的显示两个文件的不同

范例: 比较a.txt和b.txt两个文件的不同

[root@demo-c8 ~]# cat a.txt 
a
b
1
2
c
[root@demo-c8 ~]# cat b.txt 
1
2
3
[root@demo-c8 ~]# diff a.txt b.txt 
1,2d0
< a
< b
5c3
< c
---
> 3
# -u选项会以后面的文件为基准, 逐行进行比较
[root@demo-c8 ~]# diff -u a.txt b.txt 
--- a.txt   2022-09-05 18:20:03.792540321 +0800  # -代表a.txt内容
+++ b.txt   2022-09-05 16:18:21.047676537 +0800  # +代表b.txt内容
@@ -1,5 +1,3 @@
-a    # 比较第一行, 第一个文件需要把第一行a删除, 才能和第二个文件一致
-b    # 比较第二行, 第一个文件需要把第二行b删除, 才能和第二个文件一致
 1    # 第一个文件的a和b删除后, 两个文件的第一行就是一致的了, 为1
 2    # 第一个文件的a和b删除后, 两个文件的第二行就是一致的了, 为2
-c   # 第一个文件的第五行c需要被删除, 才能和第二个文件一致
+3  # 第一个文件需要加一行3, 才能和第二个文件一致

2.6.4.2 patch

diff命令的结果可以通过重定向输出到一个文本文件里, 基于这个文件, 可以用第一个文件还原出第二个文件

patch命令需要谨慎使用, 因为默认情况下, patch命令会丢失第一个文件

范例: 将a.txt和b.txt的diff结果输出到文本中, 通过a.txt和diff结果, 还原出b.txt

[root@demo-c8 ~]# diff -u a.txt b.txt > diff.log
[root@demo-c8 ~]# rm -rf b.txt 
# 默认情况下, patch会把还原回来的文件命名成a.txt, 需要用-b选项, 先把a.txt进行备份
[root@demo-c8 ~]# patch -b a.txt diff.log # -b会把a.txt先进行备份
patching file a.txt
[root@demo-c8 ~]# cat a.txt  # 此时, 新生成的a.txt为原来的b.txt
1
2
3
[root@demo-c8 ~]# cat a.txt.orig  # .orig为备份的原来的a.txt
a
b
1
2
c

练习
1、找出ifconfig “网卡名” 命令结果中本机的IPv4地址

[root@demo-c8 ~]# ifconfig | head -2 | tail -1 | tr -s ' ' | cut -d" " -f3
10.0.0.108

2、查出分区空间使用率的最大百分比值

[root@demo-c8 ~]# df | tr -s " " | cut -d " " -f1,5 | tac | sort -k2 -r
Filesystem Use%
/dev/sda1 21%
/dev/sda2 12%
tmpfs 1%
tmpfs 1%
tmpfs 1%
/dev/sda5 1%
tmpfs 0%
tmpfs 0%
devtmpfs 0%
[root@demo-c8 ~]# df | tr -s " " %| cut -d "%" -f5 | tr -d "[:alpha:]" | sort -nr 
21
12
1
1
1
1
0
0
0

[root@demo-c8 ~]# 

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

[root@demo-c8 ~]# cut -d":" -f1,3,7 /etc/passwd | sort -t":" -k2 -nr | head -1
nobody:65534:/sbin/nologin

4、查出/tmp的权限,以数字方式显示

[root@demo-c8 ~]# stat /tmp
  File: /tmp
  Size: 4096        Blocks: 8          IO Block: 4096   directory
Device: 802h/2050d  Inode: 33555360    Links: 10
Access: (1777/drwxrwxrwt)  Uid: (    0/    root)   Gid: (    0/    root)
Context: system_u:object_r:tmp_t:s0
Access: 2022-09-05 14:41:10.010785301 +0800
Modify: 2022-09-05 19:03:01.535492239 +0800
Change: 2022-09-05 19:03:01.535492239 +0800
 Birth: -
[root@demo-c8 ~]# stat /tmp | head -4 | tail -1 | cut -d " " -f2 | cut -d "/" -f1 | tr -dc "[:alnum:]"
1777[root@demo-c8 ~]# 

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

[root@demo-c8 ~]# ss -nt
State                   Recv-Q                   Send-Q                                       Local Address:Port                                       Peer Address:Port                    
ESTAB                   0                        52                                              10.0.0.108:22                                             10.0.0.1:54263 
[root@demo-c8 ~]# ss -nt | grep "^ESTAB" | tr -s " " | cut -d" " -f5 | sort | uniq -c | sort -nr
      1 10.0.0.1:54263

你可能感兴趣的:(5: 文本处理工具)