1 文本编辑工具之神VIM

1.1 vi和vim简介

在Linux中我们经常编辑修改文本文件,即由ASCII, Unicode 或其它编码的纯文字的文件。之前介绍过nano,实际工作中我们会使用更为专业,功能强大的工具。

文本编辑种类:

  • 全屏编辑器:nano(字符工具), gedit(图形化工具),vi,vim
  • 行编辑器:sed

vi

Visual editor,文本编辑器,是 Linux 必备工具之一,功能强大,学习曲线较陡峭,学习难度大

vim

VIsual editor iMproved ,和 vi 使用方法一致,但功能更为强大,不是必备软件

官网:www.vim.org

其他相关编辑器:gvim 一个Vim编辑器的图形版本。

1.2 使用 vim 初步

1.2.1 vim 命令格式

vim [OPTION]… 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 append, 在光标所在处后面输入
A 在当前光标所在行的行尾输入
o 在当前光标所在行的下方打开一个新行
O 在当前光标所在行的上方打开一个新行
  • 插入模式 — ESC—–> 命令模式
  • 命令模式 —- : —-> 扩展命令模式
  • 扩展命令模式 —-ESC,enter—-> 命令模式

1.3 扩展命令模式

按“:”进入Ex模式 ,创建一个命令提示符: 处于底部的屏幕左侧

1.3.1 扩展命令模式基本命令

w 写(存)磁盘文件
wq 写入并退出
x 写入并退出
X 加密
q 退出
q! 不存盘退出,即使更改都将丢失
r filename 读文件内容到当前文件中
w filename 将当前文件内容写入另一个文件
!command 执行命令
r!command 读入命令的输出

1.3.2 地址定界

格式:

:start_pos,end_pos CMD

1.3.2.1 地址定界格式

# #具体第#行,例如2表示第2行
#,# #从左侧#表示起始行,到右侧#表示结尾行
#,+# #从左侧#表示的起始行,加上右侧#表示的行数,范例:2,+3 表示2到5行
. #当前行
$ #最后一行
.,$-1 #当前行到倒数第二行
% #全文, 相当于1,$
/pattern/ #从当前行向下查找,直到匹配pattern的第一行,即:正则表达式
/pat1/,/pat2/ #从第一次被pat1模式匹配到的行开始,一直到第一次被pat2匹配到的行结束
#,/pat/ #从指定行开始,一直找到第一个匹配patttern的行结束
/pat/,$ #向下找到第一个匹配patttern的行到整个文件的结尾的所有行

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

d #删除
y #复制
w file #将范围内的行另存至指定文件中
r file #在指定位置插入指定文件中的所有内容

1.3.3 查找并替换

格式:

s/要查找的内容/替换为的内容/修饰符

说明:

要查找的内容:可使用基末正则表达式模式

替换为的内容:不能使用模式,但可以使用\1, \2, …等后向引用符号;还可以使用“&”引用前面查找时查找到的整个内容。

修饰符:

i #忽略大小写
g #全局替换,默认情况下,每一行只替换第一次出现
gc #全局替换,每次替换前询问

查找替换中的分隔符/可替换为其它字符,如:#,@

范例:

s@/etc@/var@g

s#/boot#/#i

1.3.4 定制vim的工作特性

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

配置文件:

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

1.3.4.1 行号

显示:set number,简写 set nu

取消显示:set nonumber, 简写 set nonu

1.3.4.2 忽略字符的大小写

启用:set ignorecase,简写 set ic

不忽略:set noic

1.3.4.3 自动缩进

启用:set autoindent,简写 set ai

禁用:set noai

1.3.4.4 复制保留格式

启用:set paste

禁用:set nopaste

1.3.4.5 显示Tab和换行符 ^I 和$显示

启用:set list

禁用:set nolist

1.3.4.6 高亮搜索

启用:set hlsearch

禁用:set nohlsearch

1.3.4.7 语法高亮

启用:syntax on

禁用:syntax off

1.3.4.8 文件格式

启用windows格式:set fileformat=dos

启用unix格式:set fileformat=unix

简写 set ff=dos|unix

1.3.4.9 Tab 用空格代替

启用:set expandtab 默认为8个空格代替Tab

禁用:set noexpandtab

简写:set et

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

启用:set tabstop=# 指定#个空格代替Tab

简写:set ts=4

1.3.4.11 设置文本宽度

set textwidth=65 (vim only)

set wrapmargin=15

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

启用:set cursorline,简写 set cul

禁用:set nocursorline

1.3.4.13 加密

启用: set key=password

禁用: set key=

1.3.4.14 了解更多

set 帮助

:help option-list

:set or :set all

1.4 命令模式

命令模式,又称为Normal模式,功能强大,只是此模式输入指令并在屏幕上显示,所以需要记忆大量的快捷按键才能更好的使用。

1.4.1 退出VIM

ZZ 保存退出

ZQ 不保存退出

1.4.2 光标跳转

字符间跳转:

h: 左 L: 右 j: 下 k: 上

#COMMAND:跳转由#指定的个数的字符

单词间跳转:

w:下一个单词的词首

e:当前或下一单词的词尾

b:当前或前一个单词的词首

#COMMAND:由#指定一次跳转的单词数

当前页跳转:

H:页首 M:页中间行 L:页底

zt:将光标所在当前行移到屏幕顶端

zz:将光标所在当前行移到屏幕中间

zb:将光标所在当前行移到屏幕底端

行首行尾跳转:

^ 跳转至行首的第一个非空白字符

0 跳转至行首

$ 跳转至行尾

行间移动:

#G 或者扩展命令模式下 :# 跳转至由第#行

G 最后一行

1G, gg 第一行

句间移动:

) 下一句 ( 上一句

段落间移动:

} 下一段 { 上一段

命令模式翻屏操作

Ctrl+f 向文件尾部翻一屏

Ctrl+b 向文件首部翻一屏

Ctrl+d 向文件尾部翻半屏

Ctrl+u 向文件首部翻半屏

1.4.3 字符编辑

x 删除光标处的字符

#x 删除光标处起始的#个字符

xp 交换光标所在处的字符及其后面字符的位置

~ 转换大小写

J 删除当前行后的换行符

1.4.4 替换命令(replace)

r 只替换光标所在处的一个字符

R 切换成REPLACE模式(在末行出现– REPLACE — 提示),按ESC回到命令模式。

1.4.5 删除命令(delete)

d 删除命令,可结合光标跳转字符,实现范围删除

d$ 删除到行尾

d^ 删除到非空行首

d0 删除到行首

dw

de

db

#COMMAND

dd: 剪切光标所在的行

#dd 多行删除

D:从当前光标位置一直删除到行尾,等同于d$

1.4.6 复制命令(yank)

y 复制,行为相似于d命令

y$

y0

y^

ye

yw

yb

#COMMAND

yy:复制行

#yy 复制多行

Y:复制整行

1.4.7 粘贴命令(paste)

p 缓冲区存的如果为整行,则粘贴当前光标所在行的下方;否则,则粘贴至当前光标所在处的后面

P 缓冲区存的如果为整行,则粘贴当前光标所在行的上方;否则,则粘贴至当前光标所在处的前面

1.4.8 改变命令(change)

c: 删除后切换成插入模式

c$

c^

c0

cb

ce

cw

#COMMAND

cc:删除当前行并输入新内容,相当于S

#cc

C:删除当前光标到行尾,并切换成插入模式,相当于c$

1.4.9 查找

/PATTERN:从当前光标所在处向文件尾部查找

?PATTERN:从当前光标所在处向文件首部查找

n:与命令同方向

N:与命令反方向

1.4.10 撤消更改

u 撤销最近的更改,相当于windows中ctrl+z

#u 撤销之前多次更改

U 撤消光标落在这行后所有此行的更改

Ctrl – r 重做最后的“撤消”更改,相当于windows中crtl+y

. 重复前一个操作

#. 重复前一个操作#次

1.4.10 高级用法

<start position><command><end position>

常见Command:y 复制、d 删除、gU 变大写、gu 变小写

范例:

0y$ 命令
0 → 先到行头
y → 从这里开始拷贝
$ → 拷贝到本行最后一个字符

di” 光标在” “之间,则删除” “之间的内容

yi( 光标在()之间,则复制()之间的内容

vi[ 光标在[]之间,则选中[]之间的内容

dtx 删除字符直到遇见光标之后的第一个 x 字符

ytx 复制字符直到遇见光标之后的第一个 x 字符

1.5 可视化模式

在末行有”– VISUAL — “指示,表示在可视化模式

允许选择的文本块

  • v 面向字符,– VISUAL —
  • V 面向整行,– VISUAL LINE —
  • ctrl-v 面向块,– VISUAL BLOCK —

可视化键可用于与移动键结合使用

w ) } 箭头等

突出显示的文字可被删除,复制,变更,过滤,搜索,替换等

范例:在文件行首插入#

输入ctrl+v 进入可视化模式
输入 G 跳到最后1行,选中每一行的第一个字符
输入 I 切换至插入模式
输入 #
按 ESC 键

1.6 多文件模式

vim FILE1 FILE2 FILE3 …

:next 下一个

:prev 前一个

:first 第一个

:last 最后一个

:wall 保存所有

:qall 不保存退出所有

:wqall保存退出所有

1.7 多窗口模式

1.7.1 多文件分割

vim -o|-O FILE1 FILE2 …

-o: 水平或上下分割

-O: 垂直或左右分割(vim only)

在窗口间切换:Ctrl+w, Arrow

1.7.2 单文件窗口分割

Ctrl+w,s:split, 水平分割,上下分屏

Ctrl+w,v:vertical, 垂直分割,左右分屏

ctrl+w,q:取消相邻窗口

ctrl+w,o:取消全部窗口

:wqall 退出

1.8 vim的寄存器

有26个命名寄存器和1个无命名寄存器,常存放不同的剪贴版内容,可以在同一个主机的不同会话(终端窗口)间共享

寄存器名称a,b,…,z,格式: ”寄存器 放在数字和命令之间

范例:

3″tyy 表示复制3行到t寄存器中 ,末行显示3 lines yanked into “t

“tp 表示将t寄存器内容粘贴

未指定,将使用无命名寄存器

有10个数字寄存器,用0,1,…,9表示,0存放最近复制内容,1存放最近删除内容。当新的文本变更和删除时,1转存到2,2转存到3,以此类推。数字寄存器不能在不同会话间共享。

1.9 标记和宏(macro)

ma 将当前位置标记为a,26个字母均可做标记, mb 、 mc 等等

‘a 跳转到a标记的位置,实用的文档内标记方法,文档中跳跃编辑时很有用

qa 录制宏 a,a为宏的名称,末行提示: recording @a

q 停止录制宏

@a 执行宏 a

@@ 重新执行上次执行的宏

1.10 编辑二进制文件

#以二进制方式打开文件
vim -b binaryfile
#扩展命令模式下,利用xxd命令转换为可读的十六进制
:%!xxd
#切换至插入模式下,编辑二进制文件
#切换至扩展命令模式下,利用xxd命令转换回二进制
:%!xxd -r
#保存退出

1.11 帮助

:help

:help topic

Use :q to exit help

2 文本常见处理工具

2.1 文件内容查看命令

2.1.1 查看文本文件内容

2.1.1.1 cat

cat 可以查看文本内容

格式:

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

常见选项

-E:显示行结束符$

-A:显示所有控制符

-n:对显示出的每一行进行编号

-b:非空行编号

-s:压缩连续的空行成一行

2.1.1.2 nl

显示行号,相当于cat -b

2.1.1.3 tac

逆向显示文本内容

2.1.1.4 rev

将同一行的内容逆向显示

2.1.2 查看非文本文件内容

2.1.2.1 hexdump

hexdump -C -n 512 /dev/sda
00000000 eb 63 90 10 8e d0 bc 00 b0 b8 00 00 8e d8 8e c0 |.c..............|
echo {a..z} | tr -d ' '|hexdump -C
00000000 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 |abcdefghijklmnop|
00000010 71 72 73 74 75 76 77 78 79 7a 0a |qrstuvwxyz.|

2.1.2.2 od

od 即 dump files in octal and other formats

[root@centos8 ~]#echo {a..z} | tr -d ' '|od -t x
0000000 64636261 68676665 6c6b6a69 706f6e6d
0000020 74737271 78777675 000a7a79
0000033
[root@centos8 ~]#echo {a..z} | tr -d ' '|od -t x1
0000000 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70
0000020 71 72 73 74 75 76 77 78 79 7a 0a
0000033
[root@centos8 ~]#echo {a..z} | tr -d ' '|od -t x1z
0000000 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 >abcdefghijklmnop<
0000020 71 72 73 74 75 76 77 78 79 7a 0a >qrstuvwxyz.<
0000033

2.1.2.3 xxd

echo {a..z} | tr -d ' '|xxd
0000000: 6162 6364 6566 6768 696a 6b6c 6d6e 6f70 abcdefghijklmnop
0000010: 7172 7374 7576 7778 797a 0a qrstuvwxyz.

2.2 分页查看文件内容

2.2.1 more

可以实现分页查看文件,可以配合管道实现输出信息的分页

格式:

more [OPTIONS...] FILE...

选项:

-d: 显示翻页及退出提示

less 也可以实现分页查看文件或STDIN输出

查看时有用的命令包括:

/文本 搜索 文本

n/N 跳到下一个 或 上一个匹配

2.2.2 less

less 命令是man命令使用的分页器

2.3 显示文本前或后行内容

2.3.1 head

可以显示文件或标准输入的前面行

head [OPTION]... [FILE]...

选项:

-c # 指定获取前#字节

-n # 指定获取前#行

-# 同上

[root@centos8 ~]#head -n 3 /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
[root@centos8 ~]#head -3 /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

2.3.2 tail

tail 和head 相反,查看文件或标准输入的倒数行

格式:

tail [OPTION]... [FILE]...

-c # 指定获取后#字节

-n # 指定获取后#行

-# 同上

-f 跟踪显示文件fd新追加的内容,常用日志监控,相当于 –follow=descriptor,当文件删除再新建同名文件,将无法继续跟踪文件

-F 跟踪文件名,相当于–follow=name –retry,当文件删除再新建同名文件,将可以继续跟踪文件tailf 类似 tail –f,当文件不增长时并不访问文件

2.4 按列抽取文本cut

cut 命令可以提取文本文件或STDIN数据的指定列

格式:

cut [OPTION]... [FILE]...

选项

-d DELIMITER: 指明分隔符,默认tab

-f FILEDS:

#: 第#个字段,例如:3

#,#[,#]:离散的多个字段,例如:1,3,6

#-#:连续的多个字段, 例如:1-6

混合使用:1-3,7

-c 按字符切割

–output-delimiter=STRING指定输出分隔符

2.5 合并多个文件paste

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

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

-d 分隔符:指定分隔符,默认用TAB

-s : 所有行合成一行显示

2.6 分析文本的工具

文本数据统计:wc

整理文本:sort

比较文件:diff和patch

2.6.1 收集文本统计数据wc

wc 命令可用于统计文件的行总数、单词总数、字节总数和字符总数可以对文件或STDIN中的数据统计。

常用选项:

-l 只计数行数

-w 只计数单词总数

-c 只计数字节总数

-m 只计数字符总数

-L 显示文件中最长行的长度

2.6.2 文本排序sort

把整理过的文本显示在STDOUT,不改变原始文件

格式:

sort [options] file(s)

常用选项:

-r 执行反方向(由上至下)整理

-R 随机排序

-n 执行按数字大小整理

-f 选项忽略(fold)字符串中的字符大小写

-u 选项(独特,unique),合并重复项,即去重

-t c 选项使用c做为字段界定符

-k # 选项按照使用c字符分隔的 # 列来整理能够使用多次

2.6.3 去重uniq

uniq命令从输入中删除前后相接的重复的行

uniq [OPTION]... [FILE]...
  -c: 显示每行重复出现的次数
  -d: 仅显示重复过的行
  -u: 仅显示不曾重复的行

2.6.4 比较文件

2.6.4.1 diff

diff 命令比较两个文件之间的区别

复制对文件改变patch

diff 命令的输出被保存在一种叫做“补丁”的文件中

使用 -u 选项来输出“统一的(unified)”diff格式文件,最适用于补丁文件

2.6.4.2 patch

patch 复制在其它文件中进行的改变(要谨慎使用)

适用 -b 选项来自动备份改变了的文件

diff -u foo.conf foo2.conf > foo.patch
patch -b foo.conf foo.patch

2.6.4.3 cmp

3 正则表达式

REGEXP: Regular Expressions,由一类特殊字符及文本字符所编写的模式,其中有些字符(元字符)。不表示字符字面意义,而表示控制或通配的功能,类似于增强版的通配符功能,但与通配符不同,通配符功能是用来处理文件名,而正则表达式是处理文本内容中字符。

正则表达式被很多程序和开发语言所广泛支持:vim, less,grep,sed,awk, nginx,mysql 等。

正则表达式分两类:

  • 基本正则表达式:BRE
  • 扩展正则表达式:ERE

正则表达式引擎:

采用不同算法,检查处理正则表达式的软件模块,如:PCRE(Perl Compatible Regular Expressions)

正则表达式的元字符分类:字符匹配、匹配次数、位置锚定、分组

帮助:man 7 regex

3.1 基本正则表达式元字符

3.1.1 字符匹配

. 匹配任意单个字符,可以是一个汉字
[] 匹配指定范围内的任意单个字符,示例:[wang] [0-9] [a-z] [a-zA-Z]
[^] 匹配指定范围外的任意单个字符,示例:[^wang]
[:alnum:] 字母和数字
[:alpha:] 代表任何英文大小写字符,亦即 A-Z, a-z
[:lower:] 小写字母,示例:[[:lower:]],相当于[a-z]
[:upper:] 大写字母
[:blank:] 空白字符(空格和制表符)
[:space:] 水平和垂直的空白字符(比[:blank:]包含的范围广)
[:cntrl:] 不可打印的控制字符(退格、删除、警铃...)
[:digit:] 十进制数字
[:xdigit:]十六进制数字
[:graph:] 可打印的非空白字符
[:print:] 可打印字符
[:punct:] 标点符号

3.1.2 匹配次数

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

* 匹配前面的字符任意次,包括0次,贪婪模式:尽可能长的匹配
.* 任意长度的任意字符
\? 匹配其前面的字符0或1次,即:可有可无
\+ 匹配其前面的字符至少1次,即:肯定有,>=1
\{n\} 匹配前面的字符n次
\{m,n\} 匹配前面的字符至少m次,至多n次
\{,n\} 匹配前面的字符至多n次,<=n
\{n,\} 匹配前面的字符至少n次

3.1.3 位置锚定

位置锚定可以用于定位出现的位置

^ 行首锚定,用于模式的最左侧
$ 行尾锚定,用于模式的最右侧
^PATTERN$ 用于模式匹配整行
^$ 空行
^[[:space:]]*$ 空白行
\< 或 \b 词首锚定,用于单词模式的左侧
\> 或 \b 词尾锚定,用于单词模式的右侧
\<PATTERN\> 匹配整个单词

3.1.4 分组其它

3.1.4.1 分组

分组:() 将多个字符捆绑在一起,当作一个整体处理,如:\(root\)+

后向引用:分组括号中的模式匹配到的内容会被正则表达式引擎记录于内部的变量中,这些变量的命名

方式为: \1, \2, \3, …

\1 表示从左侧起第一个左括号以及与之匹配右括号之间的模式所匹配到的字符

3.1.4.2 或者

或者:\|

a\|b #a或b
C\|cat #C或cat
\(C\|c\)at #Cat或cat

3.2 扩展正则表达式

3.2.1 字符匹配元字符

. 任意单个字符
[wang] 指定范围的字符
[^wang] 不在指定范围的字符
[:alnum:] 字母和数字
[:alpha:] 代表任何英文大小写字符,亦即 A-Z, a-z
[:lower:] 小写字母,示例:[[:lower:]],相当于[a-z]
[:upper:] 大写字母
[:blank:] 空白字符(空格和制表符)
[:space:] 水平和垂直的空白字符(比[:blank:]包含的范围广)
[:cntrl:] 不可打印的控制字符(退格、删除、警铃...)
[:digit:] 十进制数字
[:xdigit:]十六进制数字
[:graph:] 可打印的非空白字符
[:print:] 可打印字符
[:punct:] 标点符号

3.2.2 次数匹配

* 匹配前面字符任意次
? 0或1次
+ 1次或多次
{n} 匹配n次
{m,n} 至少m,至多n次

3.2.3 位置锚定

^ 行首
$ 行尾
\<, \b 语首
\>, \b 语尾

3.2.4 分组其它

() 分组
后向引用:\1, \2, ...
| 或者
a|b #a或b
C|cat #C或cat
(C|c)at #Cat或cat

4 文本处理三剑客

grep 命令主要对文本的(正则表达式)行基于模式进行过滤

sed:stream editor,文本编辑工具

awk:Linux上的实现gawk,文本报告生成器

4.1 文本处理三剑客之 grep

grep: Global search REgular expression and Print out the line

作用:文本搜索工具,根据用户指定的“模式”对目标文本逐行进行匹配检查;打印匹配到的行。

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

格式:

grep [OPTIONS] PATTERN [FILE...]
常见选项:
  --color=auto 对匹配到的文本着色显示
  -m # 匹配#次后停止
  -v 显示不被pattern匹配到的行
  -i 忽略字符大小写
  -n 显示匹配的行号
  -c 统计匹配的行数
  -o 仅显示匹配到的字符串
  -q 静默模式,不输出任何信息
  -A # after, 后#行
  -B # before, 前#行
  -C # context, 前后各#行
  -e 实现多个选项间的逻辑or关系,如:grep –e ‘cat ’ -e ‘dog’ file
  -w 匹配整个单词
  -E 使用ERE,相当于egrep
  -F 不支持正则表达式,相当于fgrep
  -f file 根据模式文件处理
  -r 递归目录,但不处理软链接
  -R 递归目录,但处理软链接

4.2 文本处理三剑客之 sed

4.2.1 sed 工作原理

sed 即 Stream EDitor,和 vi 不同,sed是行编辑器

Sed是从文件或管道中读取一行,处理一行,输出一行;再读取一行,再处理一行,再输出一行,直到最后一行。每当处理一行时,把当前处理的行存储在临时缓冲区中,称为模式空间(Pattern Space),接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直到文件末尾。一次处理一行的设计模式使得sed性能很高,sed在读取大文件时不会出现卡顿的现象。如果使用vi命令打开几十M上百M的文件,明显会出现有卡顿的现象,这是因为vi命令打开文件是一次性将文件加载到内存,然后再打开。Sed就避免了这种情况,一行一行的处理,打开速度非常快,执行速度也很快。

4.2.2 sed 基本用法

格式:

sed [option]... 'script;script;...' inputfile...
常用选项:
  -n 不输出模式空间内容到屏幕,即不自动打印
  -e 多点编辑
  -f /PATH/SCRIPT_FILE 从指定文件中读取编辑脚本
  -r, -E 使用扩展正则表达式
  -i.bak 备份文件并原处编辑
 script格式:
   '地址命令'
 地址格式:
    1. 不给地址:对全文进行处理
    2. 单地址:
      #:指定的行,$:最后一行
      /pattern/:被此处模式所能够匹配到的每一行
    3. 地址范围:
      #,# #从#行到第#行,3,6 从第3行到第6行
      #,+# #从#行到+#行,3,+4 表示从3行到第7行
      /pat1/,/pat2/
      #,/pat/
    4. 步进:~
      1~2 奇数行
      2~2 偶数行
  命令:
    p 打印当前模式空间内容,追加到默认输出之后
    Ip 忽略大小写输出
    d 删除模式空间匹配的行,并立即启用下一轮循环
    a [\\]text 在指定行后面追加文本,支持使用\n实现多行追加
    i [\\]text 在行前面插入文本
    c [\\]text 替换行为单行或多行文本
    w /path/file 保存模式匹配的行至指定文件
    r /path/file 读取指定文件的文本至模式空间中匹配到的行后
    = 为模式空间中的行打印行号
    ! 模式空间中匹配行取反处理
    s/pattern/string/修饰符 查找替换,支持使用其它分隔符,可以是其它形式:s@@@,s###
    替换修饰符:
      g 行内全局替换
      p 显示替换成功的行
      w /PATH/FILE 将替换成功的行保存至文件中
      I,i 忽略大小写

4.2.3 sed 高级用法

sed 中除了模式空间,还另外还支持保持空间(Hold Space),利用此空间,可以将模式空间中的数据,临时保存至保持空间,从而后续接着处理,实现更为强大的功能。

常见的高级命令:

  • P 打印模式空间开端至\n内容,并追加到默认输出之前
  • h 把模式空间中的内容覆盖至保持空间中
  • H 把模式空间中的内容追加至保持空间中
  • g 从保持空间取出数据覆盖至模式空间
  • G 从保持空间取出内容追加至模式空间
  • x 把模式空间中的内容与保持空间中的内容进行互换
  • n 读取匹配到的行的下一行覆盖至模式空间
  • N 读取匹配到的行的下一行追加至模式空间
  • d 删除模式空间中的行
  • D 如果模式空间包含换行符,则删除直到第一个换行符的模式空间中的文本,并不会读取新的输入行,而使用合成的模式空间重新启动循环。如果模式空间不包含换行符,则会像发出d命令那样启动正常的新循环

4.3 文本处理三剑客之 awk

4.3.1 awk 工作原理和基本用法说明

awk:Aho, Weinberger, Kernighan,报告生成器,格式化文本输出,GNU/Linux发布的AWK目前由自由软件基金会(FSF)进行开发和维护,通常也称它为 GNU AWK。

有多种版本:

  • AWK:原先来源于 AT & T 实验室的的AWK
  • NAWK:New awk,AT & T 实验室的AWK的升级版
  • GAWK:即GNU AWK。所有的GNU/Linux发布版都自带GAWK,它与AWK和NAWK完全兼容

gawk:模式扫描和处理语言,可以实现下面功能

  • 文本处理
  • 输出格式化的文本报表
  • 执行算数运算
  • 执行字符串操作

格式:

awk [options] 'program' var=value file…
awk [options] -f programfile var=value file…

说明:

program通常是被放在单引号中,并可以由三种部分组成

  • BEGIN语句块
  • 模式匹配的通用语句块
  • END语句块

常见选项:

  • -F “分隔符” 指明输入时用到的字段分隔符,默认的分隔符是若干个连续空白符
  • -v var=value 变量赋值

Program格式:

pattern{action statements;..}

pattern:决定动作语句何时触发及触发事件,比如:BEGIN,END,正则表达式等

action statements:对数据进行处理,放在{}内指明,常见:print, printf

awk 工作过程:

第一步:执行BEGIN{action;… }语句块中的语句

第二步:从文件或标准输入(stdin)读取一行,然后执行pattern{ action;… }语句块,它逐行扫描文件,从第一行到最后一行重复这个过程,直到文件全部被读取完毕。

第三步:当读至输入流末尾时,执行END{action;…}语句块BEGIN语句块在awk开始从输入流中读取行之前被执行,这是一个可选的语句块,比如变量初始化、打印输出表格的表头等语句通常可以写在BEGIN语句块中END语句块在awk从输入流中读取完所有的行之后即被执行,比如打印所有行的分析结果这类信息汇总都是在END语句块中完成,它也是一个可选语句块。

pattern语句块中的通用命令是最重要的部分,也是可选的。如果没有提供pattern语句块,则默认执行{print },即打印每一个读取到的行,awk读取的每一行都会执行该语句块。

分割符、域和记录

  • 由分隔符分隔的字段(列column,域field)标记$1,$2…$n称为域标识,$0为所有域,注意:和shell中变量$符含义不同
  • 文件的每一行称为记录record
  • 如果省略action,则默认执行 print $0 的操作

常用的action分类:

  • output statements:print,printf
  • Expressions:算术,比较表达式等
  • Compound statements:组合语句
  • Control statements:if, while等
  • input statements

awk控制语句:

  • { statements;… } 组合语句
  • if(condition) {statements;…}
  • if(condition) {statements;…} else {statements;…}
  • while(conditon) {statments;…}
  • do {statements;…} while(condition)
  • for(expr1;expr2;expr3) {statements;…}
  • break
  • continue
  • exit

4.3.2 动作 print

print item1, item2, ...

说明:

  • 逗号分隔符
  • 输出item可以字符串,也可是数值;当前记录的字段、变量或awk的表达式
  • 如省略item,相当于print $0
  • 固定字符需要用“ ” 引起来,而变量和数字不需要。

4.3.3 awk变量

awk中的变量分为:内置和自定义变量

  • FS:输入字段分隔符,默认为空白字符,功能相当于 -F
awk -v FS=':' '{print $1,FS,$3}' /etc/passwd
awk -v FS=":" '{print $1FS$3}' /etc/passwd
awk –F: '{print $1,$3,$7}' /etc/passwd
  • OFS:输出字段分隔符,默认为空白字符
[root@centos8 ~]#awk -v FS=':' -v OFS=':' '{print $1,$3,$7}'
/etc/passwd|head -n1
root:0:/bin/bas
  • RS:输入记录record分隔符,指定输入时的换行符
  • ORS:输出记录分隔符,输出时用指定符号代替换行符
  • NF:字段数量
  • NR:记录的编号
  • FNR:各文件分别计数,记录的编号
  • FILENAME:当前文件名
  • ARGC:命令行参数的个数
  • ARGV:数组,保存的是命令行所给定的各参数,每一个参数:ARGV[0],……

自定义变量(区分字符大小写)

-v var=value

在program中直接定义

awk -v test='hello gawk' '{print test}' /etc/fstab
awk -v test='hello gawk' 'BEGIN{print test}'
awk 'BEGIN{test="hello,gawk";print test}'
awk -F: '{sex="male";print $1,sex,age;age=18}' /etc/passwd
cat awkscript
{print script,$1,$2}
awk -F: -f awkscript script="awk" /etc/passwd

4.3.4 动作 printf

printf 可以实现格式化输出

printf “FORMAT”, item1, item2, ...

说明:

  • 必须指定FORMAT
  • 不会自动换行,需要显式给出换行控制符 \n
  • FORMAT中需要分别为后面每个item指定格式符

格式符:与item一一对应

  • %c:显示字符的ASCII码
  • %d, %i:显示十进制整数
  • %e, %E:显示科学计数法数值
  • %f:显示为浮点数
  • %g, %G:以科学计数法或浮点形式显示数值
  • %s:显示字符串
  • %u:无符号整数
  • %%:显示%自身
#[.#] 第一个数字控制显示的宽度;第二个#表示小数点后精度,如:%3.1f
- 左对齐(默认右对齐) 如:%-15s
+ 显示数值的正负符号 如:%+d
awk -F: '{printf "%s",$1}' /etc/passwd
awk -F: '{printf "%s\n",$1}' /etc/passwd
awk -F: '{printf "%20s\n",$1}' /etc/passwd
awk -F: '{printf "%-20s\n",$1}' /etc/passwd
awk -F: '{printf "%-20s %10d\n",$1,$3}' /etc/passwd
awk -F: '{printf "Username: %s\n",$1}' /etc/passwd
awk -F: '{printf “Username: %sUID:%d\n",$1,$3}' /etc/passwd
awk -F: '{printf "Username: %25sUID:%d\n",$1,$3}' /etc/passwd
awk -F: '{printf "Username: %-25sUID:%d\n",$1,$3}' /etc/passwd

4.3.5 操作符

x+y, x-y, x*y, x/y, x^y, x%y
-x:转换为负数
+x:将字符串转换为数值

字符串操作符:没有符号的操作符,字符串连接

=, +=, -=, *=, /=, %=, ^=,++, --
[root@centos8 ~]#awk 'BEGIN{i=0;print i++,i}'
0 1
[root@centos8 ~]#awk 'BEGIN{i=0;print ++i,i}'
1 1
==, !=, >, >=, <, <=
~ 左边是否和右边匹配,包含关系
!~ 是否不匹配
与:&&,并且关系
或:||,或者关系
非:!,取反
selector?if-true-expression:if-false-expression
awk -F: '{$3>=1000?usertype="Common User":usertype="SysUser";printf
"%-20s:%12s\n",$1,usertype}' /etc/passwd

4.3.6 模式PATTERN

PATTERN:根据pattern条件,过滤匹配的行,再做处理

1. 如果未指定:空模式,匹配每一行

2./regular expression/:仅处理能够模式匹配到的行,需要用/ /括起来

3. relational expression: 关系表达式,结果为“真”才会被处理

真:结果为非0值,非空字符串

假:结果为空字符串或0值

4. line ranges:行范围

不支持直接用行号,但可以使用变量NR间接指定行号

/pat1/,/pat2/ 不支持直接给出数字格式

[root@centos8 ~]#awk 'NR>=3 && NR<=6{print NR,$0}' /etc/passwd
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
6 sync:x:5:0:sync:/sbin:/bin/sync

5. BEGIN/END模式

BEGIN{}:仅在开始处理文件中的文本之前执行一次

END{}:仅在文本处理完成之后执行一次

4.3.7 条件判断 if-else

语法:

if(condition){statement;…}[else statement]
if(condition1){statement1}else if(condition2){statement2}else if(condition3)
{statement3}......else{statementN}

4.3.8 switch语句

语法:

switch(expression) {case VALUE1 or /REGEXP/: statement1; case VALUE2 or /REGEXP2/: statement2; ...; default: statementn}

4.3.9 循环while

语法:

while (condition) {statement;…}

条件“真”,进入循环;条件“假”,退出循环

使用场景:

对一行内的多个字段逐一类似处理时使用

对数组中的各元素逐一处理时使用

4.3.10 循环 do-while

语法:

do {statement;…}while(condition)

意义:无论真假,至少执行一次循环体

do-while循环

语法:do {statement;…}while(condition)

意义:无论真假,至少执行一次循环体

4.3.11 循环for

语法:

for(expr1;expr2;expr3) {statement;…}

常见用法:

for(variable assignment;condition;iteration process) {for-body}

特殊用法:能够遍历数组中的元素

for(var in array) {for-body}

4.3.12 continue和break

continue 中断本次循环

break 中断整个循环

格式:

continue [n]

break [n]

4.3.13 next

next 可以提前结束对本行处理而直接进入下一行处理(awk自身循环)

4.3.14 数组

awk的数组为关联数组

格式:

array_name[index-expression]
eg:weekdays["mon"]="Monday"

index-expression:

  • 利用数组,实现 k/v 功能
  • 可使用任意字符串;字符串要使用双引号括起来
  • 如果某数组元素事先不存在,在引用时,awk会自动创建此元素,并将其值初始化为“空串”
  • 若要判断数组中是否存在某元素,要使用“index in array”格式进行遍历
awk '!line[$0]++' dupfile
awk '{!line[$0]++;print $0, line[$0]}' dupfile

4.3.15 awk函数

awk 的函数分为内置和自定义函数

4.3.15.1 常见内置函数

数值处理:

rand():返回0和1之间一个随机数

srand():配合rand() 函数,生成随机数的种子

int():返回整数

字符串处理:

length([s]):返回指定字符串的长度

sub(r,s,[t]):对t字符串搜索r表示模式匹配的内容,并将第一个匹配内容替换为s

gsub(r,s,[t]):对t字符串进行搜索r表示的模式匹配的内容,并全部替换为s所表示的内容

split(s,array,[r]):以r为分隔符,切割字符串s,并将切割后的结果保存至array所表示的数组中,第一个索引值为1,第二个索引值为2,…

system 函数:可以awk中调用shell命令

空格是awk中的字符串连接符,如果system中需要使用awk中的变量可以使用空格分隔,或者说除了awk的变量外其他一律用””引用起来。

awk 'BEGIN{system("hostname")}'
awk 'BEGIN{score=100; system("echo your score is " score) }'

4.3.15.2 自定义函数

function name ( parameter, parameter, ... ) {
statements
return expression
}
[root@centos8 ~]#cat func.awk
function max(x,y) {
x>y?var=x:var=y
return var
}
BEGIN{print max(a,b)}
[root@centos8 ~]#awk -v a=30 -v b=20 -f func.awk
30

4.3.16 awk脚本

[root@centos8 ~]#cat test.awk
#!/bin/awk -f
#this is a awk script
{if($3>=1000)print $1,$3}
[root@centos8 ~]#chmod +x test.awk
[root@centos8 ~]#./test.awk -F: /etc/passwd
nobody 65534
wang 1000
mage 1001

向awk脚本传递参数

格式:

awkfile var=value var2=value2... Inputfile

注意:在BEGIN过程中不可用。直到首行输入完成以后,变量才可用。可以通过-v 参数,让awk在执行BEGIN之前得到变量的值。命令行中每一个指定的变量都需要一个-v参数

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注