【shell笔记>命令】grep,sed,awk

grep

grep的基本用法

grep命令是支持正则表达式的一个多用途文本搜索工具,一般格式为

grep 选项 模式 文件

选项意义
-c只输出匹配行的数量
-i搜索时忽略大小写
-h查询多文件时不显示文件名
-l只列出符合匹配的文件名,而不列出具体的匹配行
-n列出所有的匹配行,并显示行号
-s不显示不存在或无匹配文本的错误信息
-v显示不包含匹配文本的所有行
-w匹配整词
-x匹配正行
-r递归搜索,不仅搜索当前目录,而且搜索子目录
-q禁止输出任何结果,以退出状态表示搜索是否成功
-b打印匹配行距文件头部的偏移量,以字节为单位
-o与-b选项结合使用,打印匹配的词距文件头部的偏移量,以字节为单位
-E支持扩展的正则表达式
-F不支持正则表达式,按照字符串的字面意思进行匹配

grep命令的模式十分灵活,可以是字符串,也可以是变量,还可以是正则表达式。注意,无论模式是何种形式,只要模式中包含空格,就需要使用双引号将模式引起来。

grep与正则表达式

  1. 匹配行首,用元字符^
  1. 设置大小写,用-i

  2. 匹配重复字符,用., *

  3. 转义符,用\

  4. POSIX字符类

    类名意义
    [:upper:]表示大写字母[A~Z]
    [:lower:]表示小写字母[a~z]
    [:digit:]表示阿拉伯数字[0~9]
    [:alnum:]表示大小写字母和阿拉伯数字
    [:space:]表示空格键和TAB键
    [:alpha:]表示大小写字母
    [:cntrl:]表示Ctrl
    [:graph:]或[:print:]表示ASCII码
    [:xdigit:]表示16进制数字[09AFa~f]
  5. 精确匹配:用\<\>

  6. 或字符,grep需要加上-E选项才能支持它,用|表示

grep命令族

grep: 标准grep命令

egrep: 扩展grep命令,支持基本和拓展正则表达式

fgrep: 快速grep命令,不支持正则表达式

sed命令

sed是一个非交互式文本编辑器,它可对文本文件和标准输入进行编辑,标准输入可以是来自键盘输入、文件重定向、字符串、变量,甚至来自管道的文本。sed适用于以下三中场合:

  • 编辑相对交互式文本编辑器而言太大的文件。
  • 编辑命令太复杂,在交互式文本编辑器中难以输入的情况。
  • 对文件扫描一遍,但是需要执行多个编辑函数的情况。

基本用法

sed只是对缓冲区中原始文件的副本进行编辑,并不编辑原始文件。如果需要保存文件改动的内容,需要将输出重定向到另一个文件。

调用sed有三种方式,一种为Shell命令行方式,另外两种是将sed命令写入脚本文件,然后执行该脚本文件。

  1. 在Shell命令行输入命令调用sed,格式为sed [选项] 'sed命令' 输入文件
  2. sed命令插入脚本文件后,然后通过sed命令调用它,格式为sed [选项] -f sed 脚本文件 输入文件
  3. sed命令插入脚本文件后,最常用的方法是设置该脚本文件为可以执行,然后直接执行该脚本文件,格式为./sed脚本文件 输入文件

第三种方式脚本文件需要以sha-bang(#!)符号开头。无论哪种方式,如果没有指定输入文件,sed将从标准输入接收输入。常用选项有三个

选项意义
-n不打印所有的行到标准输出
-e表示将下一个字符串解析为sed编辑命令,如果只传递一个,可以省略
-f表示正在调用sed脚本文件

sed命令主要由定位文本行和sed编辑命令两部分组成,有两种方式定位文本:

  • 使用行号,指定一行,或者指定行号范围
  • 用正则表达式
选项意义
xx为指定行号
x,y指定从x到y的行号范围
/pattern/查询包含模式的行
/pattern/pattern/查询包含两个模式的行
/pattern/,x从pattern匹配行到x号行
x,/pattern/上一条反过来
x,y!查询不包括x和y行号的行

编辑命令

选项意义
p打印匹配行
=打印文件行号
a\在定位行号后追加文本信息
i\在定位行号之前插入文本信息
d删除定位行
c\用新文本替代定位文本
s使用替换模式替换相应模式
r从另一个文件中读文本
w将文本写入到一个文件
y变换字符
q第一个模式匹配后退出
l显示与八进制ASCII码等价的控制字符
{}在定位行执行的命令组
n读取下一个输入行,用下一个命令处理新的行
h将模式缓冲区的文本复制到保持缓冲区
H…追加到保持缓冲区
x互换模式缓冲区和保持缓冲区内容
g将保持模式缓冲区的内容复制到模式缓冲区
G….追加到模式缓冲区

示例

测试文件内容:

    This is a Certificate Request file:

    It should be mailed to zawu@seu.edu.cn

    =====================================================
    Certificate Subject:

    /O=Grid/OU=GlobusTest/OU=simpleCA-seugridl.seu.edu.cn/OU=seu.edu.cn/CN=globus

    The above string is known as your user certificate subject, and t uniquely identifies theis user. $88
    To install this user certificate, please save this e-mail message into the following file.

    /home/alloy/linuxshell/CH02/usercert.pem

sed -n: 不打印sed编辑对象的全部内容

wsx@wsx-ubuntu:~/桌面$ sed -n '1p' input
    This is a Certificate Request file:

wsx@wsx-ubuntu:~/桌面$ sed '1p' input
    This is a Certificate Request file:
    This is a Certificate Request file:

    It should be mailed to zawu@seu.edu.cn

    =====================================================
    Certificate Subject:

    /O=Grid/OU=GlobusTest/OU=simpleCA-seugridl.seu.edu.cn/OU=seu.edu.cn/CN=globus

    The above string is known as your user certificate subject, and t uniquely identifies theis user. $88
    To install this user certificate, please save this e-mail message into the following file.

    /home/alloy/linuxshell/CH02/usercert.pem

利用sed命令打印范围行:

wsx@wsx-ubuntu:~/桌面$ sed -n '3,6p' input 
    It should be mailed to zawu@seu.edu.cn

    =====================================================
    Certificate Subject:

sed -e: sed传递多个编辑命令时使用

wsx@wsx-ubuntu:~/桌面$ sed -n '/Certificate/=' input 
1
6

wsx@wsx-ubuntu:~/桌面$ sed -n -e '/Certificate/p' input  -e '/Certificate/=' input
    This is a Certificate Request file:
1
    Certificate Subject:
6


sed -f:调用sed脚本文件时才起作用

wsx@wsx-ubuntu:~/桌面$ sed '/file:/a\We append a new line.' input 
    This is a Certificate Request file:
We append a new line.

    It should be mailed to zawu@seu.edu.cn

    =====================================================
    Certificate Subject:

    /O=Grid/OU=GlobusTest/OU=simpleCA-seugridl.seu.edu.cn/OU=seu.edu.cn/CN=globus

    The above string is known as your user certificate subject, and t uniquely identifies theis user. $88
    To install this user certificate, please save this e-mail message into the following file.

    /home/alloy/linuxshell/CH02/usercert.pem

脚本用法:

#! /bin/sed -f 
/file:/a\       #a\表示在此处添加文本

# 添加文本
We append a new line.\
We append a another line.

sed基本编辑命令可以放在单引号内,也可放在单引号外。

sed文本定位的一组例子

  1. 匹配元字符,用转义符\进行屏蔽

    wsx@wsx-ubuntu:~/桌面$ sed -n '/\./p' input 
     It should be mailed to zawu@seu.edu.cn
     /O=Grid/OU=GlobusTest/OU=simpleCA-seugridl.seu.edu.cn/OU=seu.edu.cn/CN=globus
     The above string is known as your user certificate subject, and t uniquely identifies theis user. $88
     To install this user certificate, please save this e-mail message into the following file.
     /home/alloy/linuxshell/CH02/usercert.pem
    
    
  2. 使用元字符进行匹配

    $在sed命令中表示最后一行

    wsx@wsx-ubuntu:~/桌面$ sed -n '$p' input
     /home/alloy/linuxshell/CH02/usercert.pem
    
  3. !符号,打印不在2-10的行

    wsx@wsx-ubuntu:~/桌面$ sed -n '2,10!p' input 
     This is a Certificate Request file:
     To install this user certificate, please save this e-mail message into the following file.
    
     /home/alloy/linuxshell/CH02/usercert.pem
    
  4. 使用行号和关键字匹配限定行范围

    wsx@wsx-ubuntu:~/桌面$ sed -n '/seugrid/,$p' input 
     /O=Grid/OU=GlobusTest/OU=simpleCA-seugridl.seu.edu.cn/OU=seu.edu.cn/CN=globus
    
     The above string is known as your user certificate subject, and t uniquely identifies theis user. $88
     To install this user certificate, please save this e-mail message into the following file.
    
     /home/alloy/linuxshell/CH02/usercert.pem
    

sed基本编辑命令的一组例子

  1. 插入文本:运行脚本,以输入文件名作为参数

    #!/bin/sed -f
    /file:/i\             # i\表示此处换行插入文本
    We insert a new line.
    
  2. 修改文本

    #!/bin/sed -f
    
    /file:/c\             #c\表示此处换行修改文本
    We modify this line      #修改文本内容
    
  3. 删除文本,符号是d,不带\,与其他命令有所区别,非常灵活。下面删除第一行和最后一行。

    wsx@wsx-ubuntu:~/桌面$ sed '1d' input
    
     It should be mailed to zawu@seu.edu.cn
    
     =====================================================
     Certificate Subject:
    
     /O=Grid/OU=GlobusTest/OU=simpleCA-seugridl.seu.edu.cn/OU=seu.edu.cn/CN=globus
    
     The above string is known as your user certificate subject, and t uniquely identifies theis user. $88
     To install this user certificate, please save this e-mail message into the following file.
    
     /home/alloy/linuxshell/CH02/usercert.pem
    wsx@wsx-ubuntu:~/桌面$ sed '$d' input
     This is a Certificate Request file:
    
     It should be mailed to zawu@seu.edu.cn
    
     =====================================================
     Certificate Subject:
    
     /O=Grid/OU=GlobusTest/OU=simpleCA-seugridl.seu.edu.cn/OU=seu.edu.cn/CN=globus
    
     The above string is known as your user certificate subject, and t uniquely identifies theis user. $88
     To install this user certificate, please save this e-mail message into the following file.
    
    
  4. 替换文本,格式s/被替换的字符串/新字符串/[替换选项]

    选项意义
    g全局匹配替换(替换所有的)
    p与-n选项结合,只打印替换行
    w 文件名表示将输出定向到一个文件
    sx@wsx-ubuntu:~/桌面$ sed 's/Certificate/CERTIFICATE/' input
     This is a CERTIFICATE Request file:
    
     It should be mailed to zawu@seu.edu.cn
    
     =====================================================
     CERTIFICATE Subject:
    
     /O=Grid/OU=GlobusTest/OU=simpleCA-seugridl.seu.edu.cn/OU=seu.edu.cn/CN=globus
    
     The above string is known as your user certificate subject, and t uniquely identifies theis user. $88
     To install this user certificate, please save this e-mail message into the following file.
    
     /home/alloy/linuxshell/CH02/usercert.pem
    wsx@wsx-ubuntu:~/桌面$ sed -n 's/Certificate/CERTIFICATE/p' input
     This is a CERTIFICATE Request file:
     CERTIFICATE Subject:
    
  5. 写入到一个新文件

    wsx@wsx-ubuntu:~/桌面$ sed -n 's/Certificate/CERTIFICATE/pg' input
     This is a CERTIFICATE Request file:
     CERTIFICATE Subject:
    wsx@wsx-ubuntu:~/桌面$ 
    wsx@wsx-ubuntu:~/桌面$ sed -n '1,5 w output' input
    wsx@wsx-ubuntu:~/桌面$ cat output 
     This is a Certificate Request file:
    
     It should be mailed to zawu@seu.edu.cn
    
     =====================================================
    
    
  6. 从文件中可读入文本,格式指定地址 r 文件名

  7. 退出命令:q

  8. 变换命令:sed命令的y表示字符变换(不等长时会报错)

    wsx@wsx-ubuntu:~/桌面$ sed 'y/fmj/FMJ/' input 
     This is a CertiFicate Request File:
    
     It should be Mailed to zawu@seu.edu.cn
    
     =====================================================
     CertiFicate SubJect:
    
     /O=Grid/OU=GlobusTest/OU=siMpleCA-seugridl.seu.edu.cn/OU=seu.edu.cn/CN=globus
    
     The above string is known as your user certiFicate subJect, and t uniquely identiFies theis user. $88
     To install this user certiFicate, please save this e-Mail Message into the Following File.
    
     /hoMe/alloy/linuxshell/CH02/usercert.peM
    
    
  9. 显示控制字符:控制字符就是非打印字符,如退格键、F1键等。使用sed l命令。

  10. 在命令行执行命令组,用{}符号,与-e选项功能类似。

    wsx@wsx-ubuntu:~/桌面$ sed -n '/Certificate/{p;=}' input
        This is a Certificate Request file:
    1
        Certificate Subject:
    6
    

awk编程

awk是三位前辈开发的编程语言,awk是三位创建者的首字母。基本语言与C类似。

目前,使用的是gawk,Linux系统中/bin目录下有awkgawk两个命令,前者实际上是后者的链接。利用gawk语言可以实现数据查找、抽取文件中的数据、创建管道流命令等功能。

我们可以简单地将awk编程模型分位三个阶段:

  • 读输入文件执行的执行代码段(由BEGIN关键字标识)
  • 读取输入文件时执行代码段
  • 读输入文件之后的执行代码段(由END关键字标识)

调用方法分为两种:Sehll命令行方式;脚本执行。

awk模式匹配

任何awk语句都由模式和动作组成。模式是一组用于测试输入行是否需要执行动作的规则,动作是包含语句、函数和表达式的执行过程。awk支持所有的正则表达式元字符,以及?+两个扩展元字符。

wsx@wsx-ubuntu:~/桌面$ awk '/^$/{print "This is a blank line."}' input
This is a blank line.
This is a blank line.
This is a blank line.
This is a blank line.
This is a blank line.

单引号中间为awk命令,由两部分组成,以“/”符号分隔,^$是模式,花括号部分是动作。该awk表示一旦读入的输入文件是空行,就打印后面的字符串This is a blank line

使用脚本(将命令输入一个文件中):

wsx@wsx-ubuntu:~/桌面$ awk -f src.awk input
This is a blank line.
This is a blank line.
This is a blank line.
This is a blank line.
This is a blank line.

内容不止这些,我们先谈谈其他概念。

记录和域

awk认为输入文件是结构化的,awk将每个输入文件行定义为记录,行中的每一个字符串定义为域,域之间用空格、TAB键或其他符号进行分隔,分隔域的符号就叫分隔符。(这个结构化概念需要理解,很多命令和编程中都有涉及)

wsx@wsx-ubuntu:~/桌面$ awk '{print $2,$1,$4,$3}' sturecord 
Hao Li 025------------ njue
Ju Zhang 025---------- nju
Bin Wang 025------ seu
wsx@wsx-ubuntu:~/桌面$ awk '{print $0}' sturecord 
Li Hao  njue 025------------ 
Zhang Ju    nju 025---------- 
Wang Bin    seu 025------

可以通过对域的操作对文本进行重新排列,也可以用print $0输入所有域。

wsx@wsx-ubuntu:~/桌面$ awk 'BEGIN {one=1;two=2}{print $(one+two)}' sturecord 
njue
nju
seu

BEGIN字段中定义onetwo两个变量并赋值。

-F选项用来改变分隔符,例如只以’\t’为分隔符。

wsx@wsx-ubuntu:~/桌面$ awk -F'\t' '{print $2}' sturecord 
025------------ 
025---------- 
025------

注意-F-f的区别。

awk还提供了另一种更方便的方法改变分隔符。

wsx@wsx-ubuntu:~/桌面$ cat sturecord 
Li Hao,njue,025------------ 
Zhang Ju,nju,025---------- 
Wang Bin,seu,025------
wsx@wsx-ubuntu:~/桌面$ awk 'BEGIN {FS=","}{print $1, $3}' sturecord 
Li Hao 025------------ 
Zhang Ju 025---------- 
Wang Bin 025------

关系和布尔运算符

awk定义了一组关系运算符用于awk模式匹配。如下表

运算符意义
<小于
>大于
<=小于或等于
>=大于或等于
==等于
!=不等于
~匹配正则表达式
!~不匹配正则表达式

用/etc/passwd文件做个例子

# 第1域匹配root
wsx@wsx-ubuntu:~/桌面$ awk 'BEGIN {FS=":"} $1~/root/' /etc/passwd
# 全部域匹配root
root:x:0:0:root:/root:/bin/bash
wsx@wsx-ubuntu:~/桌面$ awk 'BEGIN {FS=":"} $0~/root/' /etc/passwd
root:x:0:0:root:/root:/bin/bash
# 全部域不匹配nologin
wsx@wsx-ubuntu:~/桌面$ awk 'BEGIN {FS=":"} $0!~/nologin/' /etc/passwd
root:x:0:0:root:/root:/bin/bash
sync:x:4:65534:sync:/bin:/bin/sync
systemd-timesync:x:100:102:systemd Time Synchronization,,,:/run/systemd:/bin/false
systemd-network:x:101:103:systemd Network Management,,,:/run/systemd/netif:/bin/false
systemd-resolve:x:102:104:systemd Resolver,,,:/run/systemd/resolve:/bin/false
systemd-bus-proxy:x:103:105:systemd Bus Proxy,,,:/run/systemd:/bin/false
syslog:x:104:108::/home/syslog:/bin/false
_apt:x:105:65534::/nonexistent:/bin/false
messagebus:x:106:110::/var/run/dbus:/bin/false
uuidd:x:107:111::/run/uuidd:/bin/false
lightdm:x:108:114:Light Display Manager:/var/lib/lightdm:/bin

awk条件语句与C类似,有if语句,if/else语句以及if/else else语句三种。

下面是支持的布尔运算符

运算符意义
||逻辑或
&&逻辑与
!逻辑非
# 多条件精确匹配
wsx@wsx-ubuntu:~/桌面$ awk 'BEGIN {FS=":"} {if($3==10||$4==10) print $0}' /etc/passwd
# 多条件模糊匹配
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
wsx@wsx-ubuntu:~/桌面$ awk 'BEGIN {FS=":"} {if($3~10||$4~10) print $0}' /etc/passwd
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
systemd-timesync:x:100:102:systemd Time Synchronization,,,:/run/systemd:/bin/false
systemd-network:x:101:103:systemd Network Management,,,:/run/systemd/netif:/bin/false
systemd-resolve:x:102:104:systemd Resolver,,,:/run/systemd/resolve:/bin/false
systemd-bus-proxy:x:103:105:systemd Bus Proxy,,,:/run/systemd:/bin/false
syslog:x:104:108::/home/syslog:/bin/false
_apt:x:105:65534::/nonexistent:/bin/false
messagebus:x:106:110::/var/run/dbus:/bin/false
uuidd:x:107:111::/run/uuidd:/bin/false
lightdm:x:108:114:Light Display Manager:/var/lib/lightdm:/bin/false
whoopsie:x:109:116::/nonexistent:/bin/false
avahi-autoipd:x:110:119:Avahi autoip daemon,,,:/var/lib/avahi-autoipd:/bin/false
wsx:x:1000:1000:wsx,,,:/home/wsx:/bin/bash
nx:x:123:1001::/var/NX/nx:/etc/NX/nxserver

表达式

一个awk表达式可以由数值、字符常量、变量、操作符、函数和正则表达式自由组合而成。

运算符意义
+
*
/
%
^或**乘方
++x在返回x之前,x变量加1
x++在返回x之后,x变量加1
wsx@wsx-ubuntu:~/桌面$ awk '/^$/{print x+=1}' input
1
2
3
4
5

系统变量

awk定义了很多内建变量用于设置环境信息,我们称为系统变量。分为两种:一种用于改变awk的默认值,例如域分隔符;第二种用于定义系统值,在处理文本时可以读取这些系统值。

变量名意义
$n当前记录的第n个域,域用FS分隔
$0记录的所有域
ARGC命令行参数的数量
ARGIND命令行中当前文件的位置(从0开始标号)
ARGV命令行参数的数组
CONVFMT数字转换格式
ENVIRON环境变量关联数组
ERRNO最后一个系统错误的描述
FIELDWIDTHS字段宽度列表,以空格键分隔
FILENAME当前文件名
FNR浏览文件的记录数
FS字段分隔符,默认是空格键
IGNORECASE布尔变量,如果为真,则进行忽略大小写的匹配
NF当前记录中的域数量
NR当前记录数
OFMT数字的输出格式
OFS输出域分隔符,默认是空格键
ORS输出记录分隔符,默认是换行符
RLENGTH由match函数所匹配的字符串长度
RS记录分隔符,默认是空格键
RSTART由match函数所匹配的字符串的第1个位置
SUBSEP数组下标分隔符,默认值是\034

格式化输出

awk借鉴C语言的语法,定义了printf输出语句。基本语法如下:

printf(格式控制符, 参数)

格式控制符分为修饰符和格式符两种,如下:

修饰符意义
左对齐
width域的步长
.prec小数点右边的位数
运算符意义
%cASCII字符
%d整型数
%e浮点数,科学计数法
%f浮点数
%o八进制数
%s字符串
%x十六进制数

内置字符串函数

awk提供了强大的内置字符串函数,用于实现文本的字符串替换、查找以及分隔等功能,下表列出:

函数名意义
gsub(r,s)在输入文件中用s替换r
gsub(r,s,t)在t中用s替换r
index(s,t)返回s中字符串第一个t的位置
length(s)返回s的长度
match(s,t)测试s是否包含匹配t的字符串
split(r,s,t)在t上将r分为序列s
sub(r,s,t)将t中第1次出现的r替换为s
substr(r,s)返回字符串r中从s开始的后缀部分
substr(r,s,t)返回字符串r中从s开始长度为t的后缀部分

向awk脚本传递参数

awk脚本内的变量可以在命令行中进行赋值,实现向awk脚本传递参数,变量赋值放在脚本之后、输入文件之前,格式为:

awk脚本 parameter=value 输入文件

条件语句和循环语句

看起来基本和C一样,框架如下——

if (条件表达式)
    动作1
[else
    动作2]
while(条件表达式)
    动作
do
    动作
while(条件表达式)
for(设置计数器初值; 测试计数器; 计数器变化)
    动作

数组

数组是存储一系列值的变量,可通过索引来访问数组的值,索引需要用中括号括起,数组的基本格式为:

array[index]=value

形式和C一样,但awk数组无需定义数组类型和大小,可以直接赋值后使用。一般用在for循环中

for (variable in array)
    do somethng with array[variable]

更多操作可以查看:http://man.linuxde.net/awk

参考:Linux Shell编程——从初学到精通(第2版)

点赞