Linux 三剑客 简介

awk、grep、sed 是 linux 操作文本的三大利器,合称文本三剑客,也是必须掌握的 linux 命令之一。三者的功能都是处理文本,但侧重点各不相同,其中属 awk 功能最强大,但也最复杂。

  • grep 更适合单纯的查找或匹配文本
  • sed 更适合编辑匹配到的文本
  • awk 更适合格式化文本,对文本进行较复杂格式处理。

正则表达式

类型

正则表达式可以使用正则表达式引擎实现,正则表达式引擎是解释正则表达式模式并使用这些模式匹配文本的基础软件。

在 Linux 中, 常用的正则表达式有:

  • POSIX 基本正则表达式(BRE)引擎
  • POSIX 扩展正则表达式(ERE)引擎

语法

格式 含义
. 匹配任意单个字符, 不能匹配空行
[] 匹配指定范围内的任意单个字符
[^] 取反[]
[:alnum:] [0-9a-zA-Z]
[:alpha:] [a-zA-z]
[:upper:] [A-Z]
[:lower:] [a-z]
[:blank:] 空白字符(空格和制表符)
[:space:] 水平和垂直的空白字符(比balnk包含的范围广)
[:cntrl:] 不可打印的控制字符(退格, 删除, 警铃)
[:digit:] 十进制数字
[:xdigit:] 十六进制数字
[:graph:] 可打印的非空白字符
[:print:] 可打印字符
[:punct:] 标点符号
* 匹配前面的字符0~n次(贪婪匹配)
\? 匹配前面的字符0/1次
\+ 匹配前面的字符1~n次
\{n, m\} 匹配前面的字符nm次**(省略n则是**0m, 省略m则是n~任意次)
^ 行首锚定
$ 行尾锚定
\< 词首锚定
\> 词尾锚定
\(\) 分组
\n 分组引用(\0代表模式匹配到的字符整体)

上述为 基本正则表达式 的元字符

扩展正则表达式 除词首和词尾的锚定字符和分组引用仍需\, 其余不需\转义

grep

简介

Linux系统中 grep 命令是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来(匹配到的标红)。grep 全称是Global Regular Expression Print,表示全局正则表达式版本,它的使用权限是所有用户。

grep 的工作方式是这样的,它在一个或多个文件中搜索字符串模板。如果模板包括空格,则必须被引用,模板后的所有字符串被看作文件名。搜索的结果被送到标准输出,不影响原文件内容。

grep 可用于 shell 脚本,因为 grep 通过返回一个状态值来说明搜索的状态,如果模板搜索成功,则返回0,如果搜索不成功,则返回1,如果搜索的文件不存在,则返回2。我们利用这些返回值就可进行一些自动化的文本处理工作。

: egrep = grep -E:扩展的正则表达式 (除了**< , > , \b** 使用其他正则都可以去掉\)(egrep已经不再维护, 官方推荐使用 grep -E)

使用

格式

1
2
3
4
用法: grep [选项]... 模式 [文件]...
在每个<文件>中查找给定<模式>。
例如:grep -i 'hello world' menu.h main.c
<模式>可以包括多个模式字符串,使用换行符进行分隔。

参数

常用参数已加粗

  • -A<显示行数>:除了显示符合范本样式的那一列之外,并显示该行之后的内容。
  • -B<显示行数>:除了显示符合样式的那一行之外,并显示该行之前的内容。
  • -C<显示行数>:除了显示符合样式的那一行之外,并显示该行之前后的内容。
  • -c:统计匹配的行数
  • -e :用指定的<模式>字符串来进行匹配操作
  • -E:扩展的正则表达式
  • -f FILE:从FILE获取PATTERN匹配
  • -F :相当于fgrep
  • -i: 忽略字符大小写的差别
  • -n:显示匹配的行号
  • -o:仅显示匹配到的字符串
  • -q: 静默模式,不输出任何信息
  • -s:不显示错误信息。
  • -v:显示不被pattern 匹配到的行,相当于[^] 反向匹配
  • -w :匹配 整个单词

sed

简介

sed 是一种流编辑器,它一次处理一内容。处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(patternspace ),接着用sed 命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。然后读入下行,执行下一个循环。如果没有使诸如 D 的特殊命令,那会在两个循环之间清空模式空间,但不会清空保留空间。这样不断重复,直到文件末尾。文件内容并没有改变,除非你使用重定向存储输出或-i

主要用来自动编辑一个或多个文件, 简化对文件的反复操作

使用

格式

1
用法: sed [选项]... {脚本(如果没有其他脚本)} [输入文件]...

选项

  • -n:不输出模式空间内容到屏幕,即不自动打印
  • -e: 多点编辑,对每行处理时,可以有多个Script
  • -f:把Script写到文件当中,在执行sed时-f 指定文件路径,如果是多个Script,换行写
  • -r:支持扩展的正则表达式
  • -i:直接将处理的结果写入文件
  • -i.bak:在将处理的结果写入文件之前备份一份

地址定界

  • 不给地址:对全文进行处理
  • 单地址:
    • #: 指定的行
    • /pattern/:被此处模式所能够匹配到的每一行
  • 地址范围:
    • #,#
    • #,+#
    • /pat1/,/pat2/
    • #,/pat1/
  • ~:步进
    • sed -n ‘1~2p’ 只打印奇数行 (1~2 从第1行,一次加2行)
    • sed -n ‘2~2p’ 只打印偶数行

编辑命令

  • d:删除模式空间匹配的行,并立即启用下一轮循环

  • p:打印当前模式空间内容,追加到默认输出之后

  • a:在指定行后面追加文本,支持使用\n实现多行追加

  • i:在行前面插入文本,支持使用\n实现多行追加

  • c:替换行为单行或多行文本,支持使用\n实现多行追加

  • w:保存模式匹配的行至指定文件

  • r:读取指定文件的文本至模式空间中匹配到的行后

  • =:为模式空间中的行打印行号

  • !:模式空间中匹配行取反处理

  • q: 退出

  • s/REGEXP/REPLACEMENT/[FLAGS]查找替换,支持使用其它分隔符,如:s@@@s###

    • REGEXP: 正则表达式,匹配的内容会被REPLACEMENT替换。

    • REPLACEMENT: 字符串,直接替换

      • \N N可以为1~9, 引用匹配分组的内容。sed -e 's/#\(Port.+\)/\1/g' /etc/ssh/sshd_config
        sed -r -e 's/#(Port.+)/\1/g' /etc/ssh/sshd_config
        上面的两行等价将以#PORT开始的行#去掉,使用-r项能够避免使用()

      • & 引用整个匹配内容sed -e s/^Port/#&/g /etc/ssh/sshd_config
        匹配以Port开头的行,并在前面加上#。

      • \L 将后面的内容转为小写,直到遇到\U或\E结束

      • \l 将后面的一个字符转为小写

      • \U 将后面的内容转为大写,直到遇到\L或\E结束

      • \u 将后面的一个字符转为大写

      • \E 结束\L,\U的转换sed -r -e 's/(\b[^\s])/\u\1/g' /etc/ssh/sshd_config
        将所有单词首字母大写。

    • FLAGS

      • g 全局替换
      • p 打印
      • = 打印行号

原理探究

sed流程图

sed 的流程基本上遵循 读取 -> 执行 -> 显示 的循环流程

  • 读取: 从输入流 (文件, 管道, 标准输入流) 读取一行并存储在名为 pattern buffer (模式空间) 的内部缓冲区中
  • 执行: 按照 sed 命令定义的顺序依次应用于刚才读取的一行数据
  • 显示: 把经过 sed 命令处理的数据发送到输出流 (文件, 管道, 标准输出流); 同时清空 pattern buffer

: 除 pattern buffer 以外, 还有 hold buffer (保存空间) 的区域供用户更好地处理数据, 这里的数据在每一周期结束后并不会清空

awk

简介

awk 是一种编程语言,用于在 linux/unix 下对文本和数据进行处理。数据可以来自标准输入(stdin)、一个或多个文件,或其它命令的输出。它支持用户自定义函数和动态正则表达式等先进功能,是linux/unix下的一个强大编程工具。它在命令行中使用,但更多是作为脚本来使用。awk有很多内建的功能,比如数组、函数等,这是它和C语言的相同之处,灵活性是awk最大的优势。

使用

语法

1
2
用法:awk [POSIX 或 GNU 风格选项] -f 脚本文件 [--] 文件 ...
用法:awk [POSIX 或 GNU 风格选项] [--] '程序' 文件 ...

选项

  • -F fs:fs指定输入分隔符,fs可以是字符串或正则表达式,如-F :
  • -v var=value:赋值一个用户定义变量,将外部变量传递给 awk
  • -f scripfile:从脚本文件中读取 awk 命令

变量

awk 作为一门编程语言, 除内置变量以外, 还可以自定义变量, 在每个变量前加 -v 选项

内置变量

  • FS输入字段分隔符默认为空白字符
  • OFS输出字段分隔符,默认为空白字符
  • RS :输入记录分隔符,指定输入时的换行符,原换行符仍有效
  • ORS :输出记录分隔符,输出时用指定符号代替换行符
  • NF :字段数量,共有多少字段, NF引用最后一列NF引用最后一列, (NF-1)引用倒数第2列
  • NR行号,后可跟多个文件,第二个文件行号继续从第一个文件最后行号开始
  • FNR :各文件分别计数, 行号,后跟一个文件和NR一样,跟多个文件,第二个文件行号从1开始
  • FILENAME :当前文件名
  • ARGC :命令行参数的个数
  • ARGV :数组,保存的是命令行所给定的各参数,查看参数

自定义变量

  1. -v var=value

    先定义变量, 之后在程序中使用

    1
    2
    3
    4
    5
    6
    7
    8
    [root@along ~]# cat awkdemo
    hello:world
    linux:redhat:lalala:hahaha
    along:love:youou
    [root@along ~]``# awk -v name="along" -F: '{print name":"$0}' awkdemo
    along:hello:world
    along:linux:redhat:lalala:hahaha
    along:along:love:you
  2. 在 program 中直接定义

    1
    2
    3
    4
    5
    6
    7
    8
    [root@along ~]# cat awk.txt
    {name="along";print name,$1}
    [root@along ~]# awk -F: -f awk.txt awkdemo
    along hello
    along linux
    along along

    [root@along ~]# awk -F: '{name="along";print name, $1}' awkdemo

命令

print

简单输出之后的参数

printf

更强大的格式化输出, 与 Cprintf 函数类似

格式: printf "FORMAT", item1, item2, ...

  1. 必须指定 FORMAT
  2. 不会自动换行, 需要显式的给出 \n
  3. FORMAT 中需要分别给后面每个 item 指定占位符

操作符

  • 算术操作符:
    • x+y, x-y, x*y, x/y, x^y, x%y
    • -x: 转换为负数
    • +x: 转换为数值
  • 字符串操作符:没有符号的操作符,字符串连接
  • 赋值操作符:
    • =, +=, -=, *=, /=, %=, ^=
    • ++, --
  • 比较操作符:
    • ==, !=, >, >=, <, <=
  • 模式匹配符:~ :左边是否和右边匹配包含 !~ :是否不匹配
  • 逻辑操作符:与&& ,或|| ,非!
  • 函数调用: function_name(argu1, argu2, …)
  • 条件表达式 (三目表达式) selector ? if-true-expression : if-false-expression
    • 注释:先判断selector,如果符合执行 ? 后的操作;否则执行 : 后的操作

PATTRN部分

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

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

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

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

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

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

  4. line ranges:行范围

    • startline(起始行),endline(结束行)/pat1/,/pat2/ 不支持直接给出数字,可以有多段,中间可以有间隔
  5. BEGIN/END 模式

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