小诺文档中心 小诺文档中心
首页
小诺博客 (opens new window)
DevOps
云原生
技术
更多
网址导航
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

kevin

运维界的菜鸟
首页
小诺博客 (opens new window)
DevOps
云原生
技术
更多
网址导航
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • shell编程

    • shell编程
    • shell正则表达式
      • 正则表达式的分类
      • 基本组成部分
      • POSIX字符类
      • 元字符
      • awk命令格式和选项
      • awk模式和操作
        • 模式
        • 操作
      • awk脚本基本结构
        • awk的工作原理
      • awk内置变量(预定义变量)
      • 将外部变量值传递给awk
      • awk运算与判断
        • 算术运算符
        • 赋值运算符
        • 逻辑运算符
        • 正则运算符
        • 关系运算符
        • 其它运算符
        • 运算级优先级表
      • awk高级输入输出
        • 读取下一条记录
        • 简单地读取一条记录
        • 关闭文件
        • 输出到一个文件
      • 设置字段定界符
      • 流程控制语句
        • 条件判断语句
        • 循环语句
        • while语句
        • for循环
        • do循环
        • 其他语句
      • 数组应用
        • 数组的定义
        • 数组相关函数
        • 二维、多维数组使用
      • 内置函数
        • 算术函数
        • 字符串函数
        • 一般函数
        • 时间函数
        • 选项
      • grep命令常见用法
        • grep递归搜索文件
      • sed的选项、命令、替换标记
        • 选项
        • 参数
        • sed命令
        • sed替换标记
        • sed元字符集
      • sed用法实例
        • 替换操作:s命令
        • 全面替换标记g
        • 定界符
        • 删除操作:d命令
        • 已匹配字符串标记&
        • 子串匹配标记\1
        • 组合多个表达式
        • 引用
        • 选定行的范围:,(逗号)
        • 多点编辑:e命令
        • 从文件读入:r命令
        • 写入文件:w命令
        • 追加(行下):a\命令
        • 插入(行上):i\命令
        • 下一个:n命令
        • 变形:y命令
        • 退出:q命令
        • 保持和获取:h命令和G命令
        • 保持和互换:h命令和x命令
        • 脚本scriptfile
        • 打印奇数行或偶数行
        • 打印匹配字符串的下一行
  • 消息队列

  • web

  • ELK

  • 自动化运维

  • linux

  • DevOps
  • shell编程
xiaonuo
2022-06-18
目录
正则表达式的分类
基本组成部分
POSIX字符类
元字符
awk命令格式和选项
awk模式和操作
模式
操作
awk脚本基本结构
awk的工作原理
awk内置变量(预定义变量)
将外部变量值传递给awk
awk运算与判断
算术运算符
赋值运算符
逻辑运算符
正则运算符
关系运算符
其它运算符
运算级优先级表
awk高级输入输出
读取下一条记录
简单地读取一条记录
关闭文件
输出到一个文件
设置字段定界符
流程控制语句
条件判断语句
循环语句
while语句
for循环
do循环
其他语句
数组应用
数组的定义
数组相关函数
二维、多维数组使用
内置函数
算术函数
字符串函数
一般函数
时间函数
选项
grep命令常见用法
grep递归搜索文件
sed的选项、命令、替换标记
选项
参数
sed命令
sed替换标记
sed元字符集
sed用法实例
替换操作:s命令
全面替换标记g
定界符
删除操作:d命令
已匹配字符串标记&
子串匹配标记\1
组合多个表达式
引用
选定行的范围:,(逗号)
多点编辑:e命令
从文件读入:r命令
写入文件:w命令
追加(行下):a\命令
插入(行上):i\命令
下一个:n命令
变形:y命令
退出:q命令
保持和获取:h命令和G命令
保持和互换:h命令和x命令
脚本scriptfile
打印奇数行或偶数行
打印匹配字符串的下一行

shell正则表达式

# Shell正则表达式

# 正则表达式的分类

  1. 基本的正则表达式(Basic Regular Expression 又叫Basic RegEx 简称BREs)
  2. 扩展的正则表达式(Extended Regular Expression 又叫Extended RegEx 简称EREs)
  3. Perl的正则表达式(Perl Regular Expression 又叫Perl RegEx 简称PREs)

# 基本组成部分

image-20211015101626139

# POSIX字符类

POSIX字符类是一个形如[:...:]的特殊元序列(meta sequence),他可以用于匹配特定的字符范围。

image-20211015101702787

# 元字符

元字符(meta character)是一种Perl风格的正则表达式,只有一部分文本处理工具支持它,并不是所有的文本处理工具都支持。

image-20211015101721596

# awk命令

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

# awk命令格式和选项

语法形式

awk [options] 'script' var=value file(s)
awk [options] -f scriptfile var=value file(s)
1
2

常用命令选项

  • -F fs fs指定输入分隔符,fs可以是字符串或正则表达式,如-F:
  • -v var=value 赋值一个用户定义变量,将外部变量传递给awk
  • -f scripfile 从脚本文件中读取awk命令
  • -m[fr] val 对val值设置内在限制,-mf选项限制分配给val的最大块数目;-mr选项限制记录的最大数目。这两个功能是Bell实验室版awk的扩展功能,在标准awk中不适用。

# awk模式和操作

awk脚本是由模式和操作组成的。

# 模式

模式可以是以下任意一个:

  • /正则表达式/:使用通配符的扩展集。
  • 关系表达式:使用运算符进行操作,可以是字符串或数字的比较测试。
  • 模式匹配表达式:用运算符~(匹配)和~!(不匹配)。
  • BEGIN语句块、pattern语句块、END语句块:参见awk的工作原理 (opens new window)

# 操作

操作由一个或多个命令、函数、表达式组成,之间由换行符或分号隔开,并位于大括号内,主要部分是:

  • 变量 (opens new window)或数组 (opens new window)赋值
  • 输出命令 (opens new window)
  • 内置函数 (opens new window)
  • 控制流语句 (opens new window)

# awk脚本基本结构

awk 'BEGIN{ print "start" } pattern{ commands } END{ print "end" }' file
1

一个awk脚本通常由:BEGIN语句块、能够使用模式匹配的通用语句块、END语句块3部分组成,这三个部分是可选的。任意一个部分都可以不出现在脚本中,脚本通常是被单引号或双引号中,例如:

awk 'BEGIN{ i=0 } { i++ } END{ print i }' filename
awk "BEGIN{ i=0 } { i++ } END{ print i }" filename

删除首行
docker ps|awk 'NR!=1{print $1}'
docker ps|awk '{if(NR>1) print $1}'
1
2
3
4
5
6

# awk的工作原理

awk 'BEGIN{ commands } pattern{ commands } END{ commands }'
1
  • 第一步:执行BEGIN{ commands }语句块中的语句;
  • 第二步:从文件或标准输入(stdin)读取一行,然后执行pattern{ commands }语句块,它逐行扫描文件,从第一行到最后一行重复这个过程,直到文件全部被读取完毕。
  • 第三步:当读至输入流末尾时,执行END{ commands }语句块。

BEGIN语句块在awk开始从输入流中读取行之前被执行,这是一个可选的语句块,比如变量初始化、打印输出表格的表头等语句通常可以写在BEGIN语句块中。

END语句块在awk从输入流中读取完所有的行之后即被执行,比如打印所有行的分析结果这类信息汇总都是在END语句块中完成,它也是一个可选语句块。

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

示例

echo -e "A line 1nA line 2" | awk 'BEGIN{ print "Start" } { print } END{ print "End" }'
Start
A line 1
A line 2
End
1
2
3
4
5

当使用不带参数的print时,它就打印当前行,当print的参数是以逗号进行分隔时,打印时则以空格作为定界符。在awk的print语句块中双引号是被当作拼接符使用,例如:

echo | awk '{ var1="v1"; var2="v2"; var3="v3"; print var1,var2,var3; }' 
v1 v2 v3
1
2

双引号拼接使用:

echo | awk '{ var1="v1"; var2="v2"; var3="v3"; print var1"="var2"="var3; }'
v1=v2=v3
1
2

{ }类似一个循环体,会对文件中的每一行进行迭代,通常变量初始化语句(如:i=0)以及打印文件头部的语句放入BEGIN语句块中,将打印的结果等语句放在END语句块中。

# awk内置变量(预定义变量)

说明:[A][N][P][G]表示第一个支持变量的工具,[A]=awk、[N]=nawk、[P]=POSIXawk、[G]=gawk

$n 当前记录的第n个字段,比如n为1表示第一个字段,n为2表示第二个字段。 
$0 这个变量包含执行过程中当前行的文本内容。
[N] ARGC 命令行参数的数目。
[G] ARGIND 命令行中当前文件的位置(从0开始算)。
[N] ARGV 包含命令行参数的数组。
[G] CONVFMT 数字转换格式(默认值为%.6g)。
[P] ENVIRON 环境变量关联数组。
[N] ERRNO 最后一个系统错误的描述。
[G] FIELDWIDTHS 字段宽度列表(用空格键分隔)。
[A] FILENAME 当前输入文件的名。
[P] FNR 同NR,但相对于当前文件。
[A] FS 字段分隔符(默认是任何空格)。
[G] IGNORECASE 如果为真,则进行忽略大小写的匹配。
[A] NF 表示字段数,在执行过程中对应于当前的字段数。
[A] NR 表示记录数,在执行过程中对应于当前的行号。
[A] OFMT 数字的输出格式(默认值是%.6g)。
[A] OFS 输出字段分隔符(默认值是一个空格)。
[A] ORS 输出记录分隔符(默认值是一个换行符)。
[A] RS 记录分隔符(默认是一个换行符)。
[N] RSTART 由match函数所匹配的字符串的第一个位置。
[N] RLENGTH 由match函数所匹配的字符串的长度。
[N] SUBSEP 数组下标分隔符(默认值是34)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

示例

echo -e "line1 f2 f3nline2 f4 f5nline3 f6 f7" | awk '{print "Line No:"NR", No of fields:"NF, "$0="$0, "$1="$1, "$2="$2, "$3="$3}' 
Line No:1, No of fields:3 $0=line1 f2 f3 $1=line1 $2=f2 $3=f3
Line No:2, No of fields:3 $0=line2 f4 f5 $1=line2 $2=f4 $3=f5
Line No:3, No of fields:3 $0=line3 f6 f7 $1=line3 $2=f6 $3=f7
1
2
3
4

使用print $NF可以打印出一行中的最后一个字段,使用$(NF-1)则是打印倒数第二个字段,其他以此类推:

echo -e "line1 f2 f3n line2 f4 f5" | awk '{print $NF}'
f3
f5
echo -e "line1 f2 f3n line2 f4 f5" | awk '{print $(NF-1)}'
f2
f4
1
2
3
4
5
6

打印每一行的第二和第三个字段:

awk '{ print $2,$3 }' filename
1

统计文件中的行数:

awk 'END{ print NR }' filename
1

以上命令只使用了END语句块,在读入每一行的时,awk会将NR更新为对应的行号,当到达最后一行NR的值就是最后一行的行号,所以END语句块中的NR就是文件的行数。

一个每一行中第一个字段值累加的例子:

seq 5 | awk 'BEGIN{ sum=0; print "总和:" } { print $1"+"; sum+=$1 } END{ print "等于"; print sum }' 
总和:
1+
2+
3+
4+
5+
等于
15
1
2
3
4
5
6
7
8
9

# 将外部变量值传递给awk

借助**-v选项**,可以将外部值(并非来自stdin)传递给awk:

VAR=10000
echo | awk -v VARIABLE=$VAR '{ print VARIABLE }'
1
2

另一种传递外部变量方法:

var1="aaa"
var2="bbb"
echo | awk '{ print v1,v2 }' v1=$var1 v2=$var2
1
2
3

当输入来自于文件时使用:

awk '{ print v1,v2 }' v1=$var1 v2=$var2 filename
1

以上方法中,变量之间用空格分隔作为awk的命令行参数跟随在BEGIN、{}和END语句块之后。

# awk运算与判断

作为一种程序设计语言所应具有的特点之一,awk支持多种运算,这些运算与C语言提供的基本相同。awk还提供了一系列内置的运算函数(如log、sqr、cos、sin等)和一些用于对字符串进行操作(运算)的函数(如length、substr等等)。这些函数的引用大大的提高了awk的运算功能。作为对条件转移指令的一部分,关系判断是每种程序设计语言都具备的功能,awk也不例外,awk中允许进行多种测试,作为样式匹配,还提供了模式匹配表达式~(匹配)和~!(不匹配)。作为对测试的一种扩充,awk也支持用逻辑运算符。

# 算术运算符

运算符 描述
+ - 加,减
* / & 乘,除与求余
+ - ! 一元加,减和逻辑非
^ *** 求幂
++ -- 增加或减少,作为前缀或后缀

例:

awk 'BEGIN{a="b";print a++,++a;}'
0 2
1
2

注意:所有用作算术运算符进行操作,操作数自动转为数值,所有非数值都变为0

# 赋值运算符

运算符 描述
= += -= *= /= %= ^= **= 赋值语句

例:

a+=5; 等价于:a=a+5; 其它同类
1

# 逻辑运算符

运算符 描述
|| 逻辑或
&& 逻辑与

例:

awk 'BEGIN{a=1;b=2;print (a>5 && b<=2),(a>5 || b<=2);}'
0 1
1
2

# 正则运算符

运算符 描述
~ ~! 匹配正则表达式和不匹配正则表达式

例:

awk 'BEGIN{a="100testa";if(a ~ /^100*/){print "ok";}}'
ok
1
2

# 关系运算符

运算符 描述
< <= > >= != == 关系运算符

例:

awk 'BEGIN{a=11;if(a >= 9){print "ok";}}'
ok
1
2

注意:> < 可以作为字符串比较,也可以用作数值比较,关键看操作数如果是字符串就会转换为字符串比较。两个都为数字才转为数值比较。字符串比较:按照ASCII码顺序比较。

# 其它运算符

运算符 描述
$ 字段引用
空格 字符串连接符
?: C条件表达式
in 数组中是否存在某键值

例:

awk 'BEGIN{a="b";print a=="b"?"ok":"err";}'
ok
awk 'BEGIN{a="b";arr[0]="b";arr[1]="c";print (a in arr);}'
0
awk 'BEGIN{a="b";arr[0]="b";arr["b"]="c";print (a in arr);}'
1
1
2
3
4
5
6

# 运算级优先级表

级别越高越优先 级别越高越优先

# awk高级输入输出

# 读取下一条记录

awk中next语句使用:在循环逐行匹配,如果遇到next,就会跳过当前行,直接忽略下面语句。而进行下一行匹配。net语句一般用于多行合并:

cat text.txt
a
b
c
d
e

awk 'NR%2==1{next}{print NR,$0;}' text.txt
2 b
4 d
1
2
3
4
5
6
7
8
9
10

当记录行号除以2余1,就跳过当前行。下面的print NR,$0也不会执行。下一行开始,程序有开始判断NR%2值。这个时候记录行号是:2 ,就会执行下面语句块:'print NR,$0'

分析发现需要将包含有“web”行进行跳过,然后需要将内容与下面行合并为一行:

cat text.txt
web01[192.168.2.100]
httpd            ok
tomcat               ok
sendmail               ok
web02[192.168.2.101]
httpd            ok
postfix               ok
web03[192.168.2.102]
mysqld            ok
httpd               ok
0
awk '/^web/{T=$0;next;}{print T":t"$0;}' test.txt
web01[192.168.2.100]:   httpd            ok
web01[192.168.2.100]:   tomcat               ok
web01[192.168.2.100]:   sendmail               ok
web02[192.168.2.101]:   httpd            ok
web02[192.168.2.101]:   postfix               ok
web03[192.168.2.102]:   mysqld            ok
web03[192.168.2.102]:   httpd               ok
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 简单地读取一条记录

awk getline用法:输出重定向需用到getline函数。getline从标准输入、管道或者当前正在处理的文件之外的其他输入文件获得输入。它负责从输入获得下一行的内容,并给NF,NR和FNR等内建变量赋值。如果得到一条记录,getline函数返回1,如果到达文件的末尾就返回0,如果出现错误,例如打开文件失败,就返回-1。

getline语法:getline var,变量var包含了特定行的内容。

awk getline从整体上来说,用法说明:

  • **当其左右无重定向符|或<时:**getline作用于当前文件,读入当前文件的第一行给其后跟的变量var或$0(无变量),应该注意到,由于awk在处理getline之前已经读入了一行,所以getline得到的返回结果是隔行的。
  • **当其左右有重定向符|或<时:**getline则作用于定向输入文件,由于该文件是刚打开,并没有被awk读入一行,只是getline读入,那么getline返回的是该文件的第一行,而不是隔行。

示例:

执行linux的date命令,并通过管道输出给getline,然后再把输出赋值给自定义变量out,并打印它:

awk 'BEGIN{ "date" | getline out; print out }' test
1

执行shell的date命令,并通过管道输出给getline,然后getline从管道中读取并将输入赋值给out,split (opens new window)函数把变量out转化成数组mon,然后打印数组mon的第二个元素:

awk 'BEGIN{ "date" | getline out; split(out,mon); print mon[2] }' test
1

命令ls (opens new window)的输出传递给geline作为输入,循环使getline从ls的输出中读取一行,并把它打印到屏幕。这里没有输入文件,因为BEGIN块在打开输入文件前执行,所以可以忽略输入文件。

awk 'BEGIN{ while( "ls" | getline) print }'
1

# 关闭文件

awk中允许在程序中关闭一个输入或输出文件,方法是使用awk的close语句。

close("filename")
1

filename可以是getline打开的文件,也可以是stdin,包含文件名的变量或者getline使用的确切命令。或一个输出文件,可以是stdout,包含文件名的变量或使用管道的确切命令。

# 输出到一个文件

awk中允许用如下方式将结果输出到一个文件:

echo | awk '{printf("hello word!n") > "datafile"}'
或
echo | awk '{printf("hello word!n") >> "datafile"}'
1
2
3

# 设置字段定界符

默认的字段定界符是空格,可以使用-F "定界符" 明确指定一个定界符:

awk -F: '{ print $NF }' /etc/passwd
或
awk 'BEGIN{ FS=":" } { print $NF }' /etc/passwd
1
2
3

在BEGIN语句块中则可以用OFS=“定界符”设置输出字段的定界符。

# 流程控制语句

在linux awk的while、do-while和for语句中允许使用break,continue语句来控制流程走向,也允许使用exit (opens new window)这样的语句来退出。break中断当前正在执行的循环并跳到循环外执行下一条语句。if 是流程选择用法。awk中,流程控制语句,语法结构,与c语言类型。有了这些语句,其实很多shell程序都可以交给awk,而且性能是非常快的。下面是各个语句用法。

# 条件判断语句

if(表达式)
  语句1
else
  语句2
1
2
3
4

格式中语句1可以是多个语句,为了方便判断和阅读,最好将多个语句用{}括起来。awk分枝结构允许嵌套,其格式为:

if(表达式)
  {语句1}
else if(表达式)
  {语句2}
else
  {语句3}
1
2
3
4
5
6

示例:

awk 'BEGIN{
test=100;
if(test>90){
  print "very good";
  }
  else if(test>60){
    print "good";
  }
  else{
    print "no pass";
  }
}'

very good
1
2
3
4
5
6
7
8
9
10
11
12
13
14

每条命令语句后面可以用;分号结尾。

# 循环语句

# while语句

while(表达式)
  {语句}
1
2

示例:

awk 'BEGIN{
test=100;
total=0;
while(i<=test){
  total+=i;
  i++;
}
print total;
}'
5050
1
2
3
4
5
6
7
8
9
10

# for循环

for循环有两种格式:

格式1:

for(变量 in 数组)
  {语句}
1
2

示例:

awk 'BEGIN{
for(k in ENVIRON){
  print k"="ENVIRON[k];
}

}'
TERM=linux
G_BROKEN_FILENAMES=1
SHLVL=1
pwd=/root/text
...
logname=root
HOME=/root
SSH_CLIENT=192.168.1.21 53087 22
1
2
3
4
5
6
7
8
9
10
11
12
13
14

注:ENVIRON是awk常量,是子典型数组。

格式2:

for(变量;条件;表达式)
  {语句}
1
2

示例:

awk 'BEGIN{
total=0;
for(i=0;i<=100;i++){
  total+=i;
}
print total;
}'
5050
1
2
3
4
5
6
7
8

# do循环

do
{语句} while(条件)
1
2

例子:

awk 'BEGIN{ 
total=0;
i=0;
do {total+=i;i++;} while(i<=100)
  print total;
}'
5050
1
2
3
4
5
6
7

# 其他语句

  • break 当 break 语句用于 while 或 for 语句时,导致退出程序循环。
  • continue 当 continue 语句用于 while 或 for 语句时,使程序循环移动到下一个迭代。
  • next 能能够导致读入下一个输入行,并返回到脚本的顶部。这可以避免对当前输入行执行其他的操作过程。
  • exit 语句使主输入循环退出并将控制转移到END,如果END存在的话。如果没有定义END规则,或在END中应用exit语句,则终止脚本的执行。

# 数组应用

数组是awk的灵魂,处理文本中最不能少的就是它的数组处理。因为数组索引(下标)可以是数字和字符串在awk中数组叫做关联数组(associative arrays)。awk 中的数组不必提前声明,也不必声明大小。数组元素用0或空字符串来初始化,这根据上下文而定。

# 数组的定义

数字做数组索引(下标):

Array[1]="sun"
Array[2]="kai"
1
2

字符串做数组索引(下标):

Array["first"]="www"
Array["last"]="name"
Array["birth"]="1987"
1
2
3

使用中print Array[1]会打印出sun;使用print Array[2]会打印出kai;使用print["birth"]会得到1987。

读取数组的值

{ for(item in array) {print array[item]}; }       #输出的顺序是随机的
{ for(i=1;i<=len;i++) {print array[i]}; }         #Len是数组的长度
1
2

# 数组相关函数

得到数组长度:

awk 'BEGIN{info="it is a test";lens=split(info,tA," ");print length(tA),lens;}'
4 4
1
2

length返回字符串以及数组长度,split进行分割字符串为数组,也会返回分割得到数组长度。

awk 'BEGIN{info="it is a test";split(info,tA," ");print asort(tA);}'
4
1
2

asort对数组进行排序,返回数组长度。

输出数组内容(无序,有序输出):

awk 'BEGIN{info="it is a test";split(info,tA," ");for(k in tA){print k,tA[k];}}'
4 test
1 it
2 is
3 a 
1
2
3
4
5

for…in输出,因为数组是关联数组,默认是无序的。所以通过for…in得到是无序的数组。如果需要得到有序数组,需要通过下标获得。

awk 'BEGIN{info="it is a test";tlen=split(info,tA," ");for(k=1;k<=tlen;k++){print k,tA[k];}}'
1 it
2 is
3 a
4 test
1
2
3
4
5

注意:数组下标是从1开始,与C数组不一样。

判断键值存在以及删除键值:

#错误的判断方法:
awk 'BEGIN{tB["a"]="a1";tB["b"]="b1";if(tB["c"]!="1"){print "no found";};for(k in tB){print k,tB[k];}}' 
no found
a a1
b b1
c
1
2
3
4
5
6

以上出现奇怪问题,tB[“c”]没有定义,但是循环时候,发现已经存在该键值,它的值为空,这里需要注意,awk数组是关联数组,只要通过数组引用它的key,就会自动创建改序列。

#正确判断方法:
awk 'BEGIN{tB["a"]="a1";tB["b"]="b1";if( "c" in tB){print "ok";};for(k in tB){print k,tB[k];}}'  
a a1
b b1
1
2
3
4

if(key in array)通过这种方法判断数组中是否包含key键值。

#删除键值:
[chengmo@localhost ~]$ awk 'BEGIN{tB["a"]="a1";tB["b"]="b1";delete tB["a"];for(k in tB){print k,tB[k];}}'                     
b b1
1
2
3

delete array[key]可以删除,对应数组key的,序列值。

# 二维、多维数组使用

awk的多维数组在本质上是一维数组,更确切一点,awk在存储上并不支持多维数组。awk提供了逻辑上模拟二维数组的访问方式。例如,array[2,4]=1这样的访问是允许的。awk使用一个特殊的字符串SUBSEP(�34)作为分割字段,在上面的例子中,关联数组array存储的键值实际上是2�344。

类似一维数组的成员测试,多维数组可以使用if ( (i,j) in array)这样的语法,但是下标必须放置在圆括号中。类似一维数组的循环访问,多维数组使用for ( item in array )这样的语法遍历数组。与一维数组不同的是,多维数组必须使用split()函数来访问单独的下标分量。

awk 'BEGIN{
for(i=1;i<=9;i++){
  for(j=1;j<=9;j++){
    tarr[i,j]=i*j; print i,"*",j,"=",tarr[i,j];
  }
}
}'
1 * 1 = 1
1 * 2 = 2
1 * 3 = 3
1 * 4 = 4
1 * 5 = 5
1 * 6 = 6 
...
9 * 6 = 54
9 * 7 = 63
9 * 8 = 72
9 * 9 = 81
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

可以通过array[k,k2]引用获得数组内容。

另一种方法:

awk 'BEGIN{
for(i=1;i<=9;i++){
  for(j=1;j<=9;j++){
    tarr[i,j]=i*j;
  }
}
for(m in tarr){
  split(m,tarr2,SUBSEP); print tarr2[1],"*",tarr2[2],"=",tarr[m];
}
}'
1
2
3
4
5
6
7
8
9
10

# 内置函数

awk内置函数,主要分以下3种类似:算数函数、字符串函数、其它一般函数、时间函数。

# 算术函数

格式 描述
atan2( y, x ) 返回 y/x 的反正切。
cos( x ) 返回 x 的余弦;x 是弧度。
sin( x ) 返回 x 的正弦;x 是弧度。
exp( x ) 返回 x 幂函数。
log( x ) 返回 x 的自然对数。
sqrt( x ) 返回 x 平方根。
int( x ) 返回 x 的截断至整数的值。
rand( ) 返回任意数字 n,其中 0 <= n < 1。
srand( [expr (opens new window)] ) 将 rand 函数的种子值设置为 Expr 参数的值,或如果省略 Expr 参数则使用某天的时间。返回先前的种子值。

举例说明:

awk 'BEGIN{OFMT="%.3f";fs=sin(1);fe=exp(10);fl=log(10);fi=int(3.1415);print fs,fe,fl,fi;}'
0.841 22026.466 2.303 3
1
2

OFMT 设置输出数据格式是保留3位小数。

获得随机数:

awk 'BEGIN{srand();fr=int(100*rand());print fr;}'
78
awk 'BEGIN{srand();fr=int(100*rand());print fr;}'
31
awk 'BEGIN{srand();fr=int(100*rand());print fr;}'
41 
1
2
3
4
5
6

# 字符串函数

格式 描述
gsub( Ere, Repl, [ In ] ) 除了正则表达式所有具体值被替代这点,它和 sub 函数完全一样地执行。
sub( Ere, Repl, [ In ] ) 用 Repl 参数指定的字符串替换 In 参数指定的字符串中的由 Ere 参数指定的扩展正则表达式的第一个具体值。sub 函数返回替换的数量。出现在 Repl 参数指定的字符串中的 &(和符号)由 In 参数指定的与 Ere 参数的指定的扩展正则表达式匹配的字符串替换。如果未指定 In 参数,缺省值是整个记录($0 记录变量)。
index( String1, String2 ) 在由 String1 参数指定的字符串(其中有出现 String2 指定的参数)中,返回位置,从 1 开始编号。如果 String2 参数不在 String1 参数中出现,则返回 0(零)。
length [(String)] 返回 String 参数指定的字符串的长度(字符形式)。如果未给出 String 参数,则返回整个记录的长度($0 记录变量)。
blength [(String)] 返回 String 参数指定的字符串的长度(以字节为单位)。如果未给出 String 参数,则返回整个记录的长度($0 记录变量)。
substr( String, M, [ N ] ) 返回具有 N 参数指定的字符数量子串。子串从 String 参数指定的字符串取得,其字符以 M 参数指定的位置开始。M 参数指定为将 String 参数中的第一个字符作为编号 1。如果未指定 N 参数,则子串的长度将是 M 参数指定的位置到 String 参数的末尾 的长度。
match( String, Ere ) 在 String 参数指定的字符串(Ere 参数指定的扩展正则表达式出现在其中)中返回位置(字符形式),从 1 开始编号,或如果 Ere 参数不出现,则返回 0(零)。RSTART 特殊变量设置为返回值。RLENGTH 特殊变量设置为匹配的字符串的长度,或如果未找到任何匹配,则设置为 -1(负一)。
split( String, A, [Ere] ) 将 String 参数指定的参数分割为数组元素 A[1], A[2], . . ., A[n],并返回 n 变量的值。此分隔可以通过 Ere 参数指定的扩展正则表达式进行,或用当前字段分隔符(FS 特殊变量)来进行(如果没有给出 Ere 参数)。除非上下文指明特定的元素还应具有一个数字值,否则 A 数组中的元素用字符串值来创建。
tolower( String ) 返回 String 参数指定的字符串,字符串中每个大写字符将更改为小写。大写和小写的映射由当前语言环境的 LC_CTYPE 范畴定义。
toupper( String ) 返回 String 参数指定的字符串,字符串中每个小写字符将更改为大写。大写和小写的映射由当前语言环境的 LC_CTYPE 范畴定义。
sprintf(Format, Expr, Expr, . . . ) 根据 Format 参数指定的 printf 子例程格式字符串来格式化 Expr 参数指定的表达式并返回最后生成的字符串。

注:Ere都可以是正则表达式。

gsub,sub使用

awk 'BEGIN{info="this is a test2010test!";gsub(/[0-9]+/,"!",info);print info}'
this is a test!test!
1
2

在 info中查找满足正则表达式,/[0-9]+/用””替换,并且替换后的值,赋值给info 未给info值,默认是$0

查找字符串(index使用)

awk 'BEGIN{info="this is a test2010test!";print index(info,"test")?"ok":"no found";}'
ok
1
2

未找到,返回0

正则表达式匹配查找(match使用)

awk 'BEGIN{info="this is a test2010test!";print match(info,/[0-9]+/)?"ok":"no found";}'
ok
1
2

截取字符串(substr使用)

[wangsl@centos5 ~]$ awk 'BEGIN{info="this is a test2010test!";print substr(info,4,10);}'
s is a tes
1
2

从第 4个 字符开始,截取10个长度字符串

字符串分割(split使用)

awk 'BEGIN{info="this is a test";split(info,tA," ");print length(tA);for(k in tA){print k,tA[k];}}'
4
4 test
1 this
2 is
3 a
1
2
3
4
5
6

分割info,动态创建数组tA,这里比较有意思,awk for …in循环,是一个无序的循环。 并不是从数组下标1…n ,因此使用时候需要注意。

格式化字符串输出(sprintf使用)

格式化字符串格式:

其中格式化字符串包括两部分内容:一部分是正常字符,这些字符将按原样输出; 另一部分是格式化规定字符,以"%"开始,后跟一个或几个规定字符,用来确定输出内容格式。

格式 描述
%d 十进制有符号整数
%u 十进制无符号整数
%f 浮点数
%s 字符串
%c 单个字符
%p 指针的值
%e 指数形式的浮点数
%x %X 无符号以十六进制表示的整数
%o 无符号以八进制表示的整数
%g 自动选择合适的表示法
awk 'BEGIN{n1=124.113;n2=-1.224;n3=1.2345; printf("%.2f,%.2u,%.2g,%X,%on",n1,n2,n3,n1,n1);}'
124.11,18446744073709551615,1.2,7C,174
1
2

# 一般函数

格式 描述
close( Expression ) 用同一个带字符串值的 Expression 参数来关闭由 print 或 printf 语句打开的或调用 getline 函数打开的文件或管道。如果文件或管道成功关闭,则返回 0;其它情况下返回非零值。如果打算写一个文件,并稍后在同一个程序中读取文件,则 close 语句是必需的。
system(command (opens new window) ) 执行 Command 参数指定的命令,并返回退出状态。等同于 system 子例程。
Expression | getline [ Variable ] 从来自 Expression 参数指定的命令的输出中通过管道传送的流中读取一个输入记录,并将该记录的值指定给 Variable 参数指定的变量。如果当前未打开将 Expression 参数的值作为其命令名称的流,则创建流。创建的流等同于调用 popen 子例程,此时 Command 参数取 Expression 参数的值且 Mode 参数设置为一个是 r 的值。只要流保留打开且 Expression 参数求得同一个字符串,则对 getline 函数的每次后续调用读取另一个记录。如果未指定 Variable 参数,则 $0 记录变量和 NF 特殊变量设置为从流读取的记录。
getline [ Variable ] < Expression 从 Expression 参数指定的文件读取输入的下一个记录,并将 Variable 参数指定的变量设置为该记录的值。只要流保留打开且 Expression 参数对同一个字符串求值,则对 getline 函数的每次后续调用读取另一个记录。如果未指定 Variable 参数,则 $0 记录变量和 NF 特殊变量设置为从流读取的记录。
getline [ Variable ] 将 Variable 参数指定的变量设置为从当前输入文件读取的下一个输入记录。如果未指定 Variable 参数,则 $0 记录变量设置为该记录的值,还将设置 NF、NR 和 FNR 特殊变量。

打开外部文件(close用法)

awk 'BEGIN{while("cat /etc/passwd"|getline){print $0;};close("/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
1
2
3
4

逐行读取外部文件(getline使用方法)

awk 'BEGIN{while(getline < "/etc/passwd"){print $0;};close("/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
awk 'BEGIN{print "Enter your name:";getline name;print name;}'
Enter your name:
chengmo
chengmo
1
2
3
4
5
6
7
8

调用外部应用程序(system使用方法)

awk 'BEGIN{b=system("ls -al");print b;}'
total 42092
drwxr-xr-x 14 chengmo chengmo     4096 09-30 17:47 .
drwxr-xr-x 95 root   root       4096 10-08 14:01 ..
1
2
3
4

b返回值,是执行结果。

# 时间函数

格式 描述
函数名 说明
mktime( YYYY MM dd (opens new window) HH MM ss (opens new window)[ DST]) 生成时间格式
strftime([format [, timestamp]]) 格式化时间输出,将时间戳转为时间字符串 具体格式,见下表.
systime() 得到时间戳,返回从1970年1月1日开始到当前时间(不计闰年)的整秒数

建指定时间(mktime使用)

awk 'BEGIN{tstamp=mktime("2001 01 01 12 12 12");print strftime("%c",tstamp);}'
2001年01月01日 星期一 12时12分12秒
awk 'BEGIN{tstamp1=mktime("2001 01 01 12 12 12");tstamp2=mktime("2001 02 01 0 0 0");print tstamp2-tstamp1;}'
2634468
1
2
3
4

求2个时间段中间时间差,介绍了strftime使用方法

awk 'BEGIN{tstamp1=mktime("2001 01 01 12 12 12");tstamp2=systime();print tstamp2-tstamp1;}' 
308201392
1
2

strftime日期和时间格式说明符

格式 描述
%a 星期几的缩写(Sun)
%A 星期几的完整写法(Sunday)
%b 月名的缩写(Oct)
%B 月名的完整写法(October)
%c 本地日期和时间
%d 十进制日期
%D 日期 08/20/99
%e 日期,如果只有一位会补上一个空格
%H 用十进制表示24小时格式的小时
%I 用十进制表示12小时格式的小时
%j 从1月1日起一年中的第几天
%m 十进制表示的月份
%M 十进制表示的分钟
%p 12小时表示法(AM/PM)
%S 十进制表示的秒
%U 十进制表示的一年中的第几个星期(星期天作为一个星期的开始)
%w (opens new window) 十进制表示的星期几(星期天是0)
%W 十进制表示的一年中的第几个星期(星期一作为一个星期的开始)
%x 重新设置本地日期(08/20/99)
%X 重新设置本地时间(12:00:00)
%y 两位数字表示的年(99)
%Y 当前月份
%Z 时区(PDT)
%% 百分号(%)

# grep命令

grep(global search regular expression(RE) and print out the line,全面搜索正则表达式并把行打印出来)是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来。

# 选项

-a 不要忽略二进制数据。
-A<显示列数> 除了显示符合范本样式的那一行之外,并显示该行之后的内容。
-b 在显示符合范本样式的那一行之外,并显示该行之前的内容。
-c 计算符合范本样式的列数。
-C<显示列数>或-<显示列数>  除了显示符合范本样式的那一列之外,并显示该列之前后的内容。
-d<进行动作> 当指定要查找的是目录而非文件时,必须使用这项参数,否则grep命令将回报信息并停止动作。
-e<范本样式> 指定字符串作为查找文件内容的范本样式。
-E 将范本样式为延伸的普通表示法来使用,意味着使用能使用扩展正则表达式。
-f<范本文件> 指定范本文件,其内容有一个或多个范本样式,让grep查找符合范本条件的文件内容,格式为每一列的范本样式。
-F 将范本样式视为固定字符串的列表。
-G 将范本样式视为普通的表示法来使用。
-h 在显示符合范本样式的那一列之前,不标示该列所属的文件名称。
-H 在显示符合范本样式的那一列之前,标示该列的文件名称。
-i 忽略字符大小写的差别。
-l 列出文件内容符合指定的范本样式的文件名称。
-L 列出文件内容不符合指定的范本样式的文件名称。
-n 在显示符合范本样式的那一列之前,标示出该列的编号。
-q 不显示任何信息。
-R/-r 此参数的效果和指定“-d recurse”参数相同。
-s 不显示错误信息。
-v 反转查找。
-w 只显示全字符合的列。
-x 只显示全列符合的列。
-y 此参数效果跟“-i”相同。
-o 只输出文件中匹配到的部分。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# grep命令常见用法

在文件中搜索一个单词,命令会返回一个包含**“match_pattern”**的文本行:

grep match_pattern file_name
grep "match_pattern" file_name
1
2

在多个文件中查找:

grep "match_pattern" file_1 file_2 file_3 ...
1

输出除之外的所有行 -v 选项:

grep -v "match_pattern" file_name
1

标记匹配颜色 --color=auto 选项:

grep "match_pattern" file_name --color=auto
1

使用正则表达式 -E 选项:

grep -E "[1-9]+"
或
egrep "[1-9]+"
1
2
3

只输出文件中匹配到的部分 -o 选项:

echo this is a test line. | grep -o -E "[a-z]+\."
line.

echo this is a test line. | egrep -o "[a-z]+\."
line.
1
2
3
4
5

统计文件或者文本中包含匹配字符串的行数 -c 选项:

grep -c "text" file_name
1

输出包含匹配字符串的行数 -n 选项:

grep "text" -n file_name
或
cat file_name | grep "text" -n

#多个文件
grep "text" -n file_1 file_2
1
2
3
4
5
6

打印样式匹配所位于的字符或字节偏移:

echo gun is not unix | grep -b -o "not"
7:not

#一行中字符串的字符便宜是从该行的第一个字符开始计算,起始值为0。选项 -b -o 一般总是配合使用。
1
2
3
4

搜索多个文件并查找匹配文本在哪些文件中:

grep -l "text" file1 file2 file3...
1

# grep递归搜索文件

在多级目录中对文本进行递归搜索:

grep "text" . -r -n
# .表示当前目录。
1
2

忽略匹配样式中的字符大小写:

echo "hello world" | grep -i "HELLO"
hello
1
2

选项 -e 制动多个匹配样式:

echo this is a text line | grep -e "is" -e "line" -o
is
line

#也可以使用-f选项来匹配多个样式,在样式文件中逐行写出需要匹配的字符。
cat patfile
aaa
bbb

echo aaa bbb ccc ddd eee | grep -f patfile -o
1
2
3
4
5
6
7
8
9
10

在grep搜索结果中包括或者排除指定文件:

#只在目录中所有的.php和.html文件中递归搜索字符"main()"
grep "main()" . -r --include *.{php,html}

#在搜索结果中排除所有README文件
grep "main()" . -r --exclude "README"

#在搜索结果中排除filelist文件列表里的文件
grep "main()" . -r --exclude-from filelist
1
2
3
4
5
6
7
8

使用0值字节后缀的grep与xargs (opens new window):

#测试文件:
echo "aaa" > file1
echo "bbb" > file2
echo "aaa" > file3

grep "aaa" file* -lZ | xargs -0 rm

#执行后会删除file1和file3,grep输出用-Z选项来指定以0值字节作为终结符文件名(\0),xargs -0 读取输入并用0值字节终结符分隔文件名,然后删除匹配文件,-Z通常和-l结合使用。
1
2
3
4
5
6
7
8

grep静默输出:

grep -q "test" filename

#不会输出任何信息,如果命令运行成功返回0,失败则返回非0值。一般用于条件测试。
1
2
3

打印出匹配文本之前或者之后的行:

#显示匹配某个结果之后的3行,使用 -A 选项:
seq 10 | grep "5" -A 3
5
6
7
8

#显示匹配某个结果之前的3行,使用 -B 选项:
seq 10 | grep "5" -B 3
2
3
4
5

#显示匹配某个结果的前三行和后三行,使用 -C 选项:
seq 10 | grep "5" -C 3
2
3
4
5
6
7
8

#如果匹配结果有多个,会用“--”作为各匹配结果之间的分隔符:
echo -e "a\nb\nc\na\nb\nc" | grep a -A 1
a
b
--
a
b
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

# sed命令

sed是一种流编辑器,它是文本处理中非常中的工具,能够完美的配合正则表达式使用,功能不同凡响。处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直到文件末尾。文件内容并没有 改变,除非你使用重定向存储输出。Sed主要用来自动编辑一个或多个文件;简化对文件的反复操作;编写转换程序等。

# sed的选项、命令、替换标记

命令格式

sed [options] 'command' file(s)
sed [options] -f scriptfile file(s)
1
2

# 选项

-e<script>或--expression=<script>:以选项中的指定的script来处理输入的文本文件;
-f<script文件>或--file=<script文件>:以选项中指定的script文件来处理输入的文本文件;
-h或--help:显示帮助;
-n或--quiet或——silent:仅显示script处理后的结果;
-V或--version:显示版本信息。
1
2
3
4
5

# 参数

文件:指定待处理的文本文件列表。

# sed命令

a\ 在当前行下面插入文本。
i\ 在当前行上面插入文本。
c\ 把选定的行改为新的文本。
d 删除,删除选择的行。
D 删除模板块的第一行。
s 替换指定字符
h 拷贝模板块的内容到内存中的缓冲区。
H 追加模板块的内容到内存中的缓冲区。
g 获得内存缓冲区的内容,并替代当前模板块中的文本。
G 获得内存缓冲区的内容,并追加到当前模板块文本的后面。
l 列表不能打印字符的清单。
n 读取下一个输入行,用下一个命令处理新的行而不是用第一个命令。
N 追加下一个输入行到模板块后面并在二者间嵌入一个新行,改变当前行号码。
p 打印模板块的行。
P(大写) 打印模板块的第一行。
q 退出Sed。
b lable 分支到脚本中带有标记的地方,如果分支不存在则分支到脚本的末尾。
r file 从file中读行。
t label if分支,从最后一行开始,条件一旦满足或者T,t命令,将导致分支到带有标号的命令处,或者到脚本的末尾。
T label 错误分支,从最后一行开始,一旦发生错误或者T,t命令,将导致分支到带有标号的命令处,或者到脚本的末尾。
w file 写并追加模板块到file末尾。  
W file 写并追加模板块的第一行到file末尾。  
! 表示后面的命令对所有没有被选定的行发生作用。  
= 打印当前行号码。  
# 把注释扩展到下一个换行符以前。  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# sed替换标记

g 表示行内全面替换。  
p 表示打印行。  
w 表示把行写入一个文件。  
x 表示互换模板块中的文本和缓冲区中的文本。  
y 表示把一个字符翻译为另外的字符(但是不用于正则表达式)
\1 子串匹配标记
& 已匹配字符串标记
1
2
3
4
5
6
7

# sed元字符集

^ 匹配行开始,如:/^sed/匹配所有以sed开头的行。
$ 匹配行结束,如:/sed$/匹配所有以sed结尾的行。
. 匹配一个非换行符的任意字符,如:/s.d/匹配s后接一个任意字符,最后是d。
* 匹配0个或多个字符,如:/*sed/匹配所有模板是一个或多个空格后紧跟sed的行。
[] 匹配一个指定范围内的字符,如/[ss]ed/匹配sed和Sed。  
[^] 匹配一个不在指定范围内的字符,如:/[^A-RT-Z]ed/匹配不包含A-R和T-Z的一个字母开头,紧跟ed的行。
\(..\) 匹配子串,保存匹配的字符,如s/\(love\)able/\1rs,loveable被替换成lovers。
& 保存搜索字符用来替换其他字符,如s/love/**&**/,love这成**love**。
\< 匹配单词的开始,如:/\<love/匹配包含以love开头的单词的行。
\> 匹配单词的结束,如/love\>/匹配包含以love结尾的单词的行。
x\{m\} 重复字符x,m次,如:/0\{5\}/匹配包含5个0的行。
x\{m,\} 重复字符x,至少m次,如:/0\{5,\}/匹配至少有5个0的行。
x\{m,n\} 重复字符x,至少m次,不多于n次,如:/0\{5,10\}/匹配5~10个0的行。
1
2
3
4
5
6
7
8
9
10
11
12
13

# sed用法实例

# 替换操作:s命令

替换文本中的字符串:

sed 's/book/books/' file
1

-n选项和p命令一起使用表示只打印那些发生替换的行:

sed -n 's/test (opens new window)/TEST/p' file

直接编辑文件选项-i,会匹配file文件中每一行的第一个book替换为books:

sed -i 's/book/books/g' file
1

# 全面替换标记g

使用后缀 /g 标记会替换每一行中的所有匹配:

sed 's/book/books/g' file
1

当需要从第N处匹配开始替换时,可以使用 /Ng:

echo sksksksksksk | sed 's/sk/SK/2g'
skSKSKSKSKSK

echo sksksksksksk | sed 's/sk/SK/3g'
skskSKSKSKSK

echo sksksksksksk | sed 's/sk/SK/4g'
skskskSKSKSK
1
2
3
4
5
6
7
8

# 定界符

以上命令中字符 / 在sed中作为定界符使用,也可以使用任意的定界符:

sed 's:test:TEXT:g'
sed 's|test|TEXT|g'
1
2

定界符出现在样式内部时,需要进行转义:

sed 's/\/bin/\/usr\/local\/bin/g'
1

# 删除操作:d命令

删除空白行:

sed '/^$/d' file
1

删除文件的第2行:

sed '2d' file
1

删除文件的第2行到末尾所有行:

sed '2,$d' file
1

删除文件最后一行:

sed '$d' file
1

删除文件中所有开头是test的行:

sed '/^test/'d file
1

# 已匹配字符串标记&

正则表达式 \w+ 匹配每一个单词,使用 [&] 替换它,& 对应于之前所匹配到的单词:

echo this is a test line | sed 's/\w\+/[&]/g'
[this] [is] [a] [test] [line]
1
2

所有以192.168.0.1开头的行都会被替换成它自已加localhost:

sed 's/^192.168.0.1/&localhost/' file
192.168.0.1localhost
1
2

# 子串匹配标记\1

匹配给定样式的其中一部分:

echo this is digit 7 in a number | sed 's/digit \([0-9]\)/\1/'
this is 7 in a number
1
2

命令中 digit 7,被替换成了 7。样式匹配到的子串是 7,(..) 用于匹配子串,对于匹配到的第一个子串就标记为 \1,依此类推匹配到的第二个结果就是 \2,例如:

echo aaa BBB | sed 's/\([a-z]\+\) \([A-Z]\+\)/\2 \1/'
BBB aaa
1
2

love被标记为1,所有loveable会被替换成lovers,并打印出来:

sed -n 's/\(love\)able/\1rs/p' file
1

# 组合多个表达式

sed '表达式' | sed '表达式'

等价于:

sed '表达式; 表达式'
1
2
3
4
5

# 引用

sed表达式可以使用单引号来引用,但是如果表达式内部包含变量字符串,就需要使用双引号。

test=hello
echo hello WORLD | sed "s/$test/HELLO"
HELLO WORLD
1
2
3

# 选定行的范围:,(逗号)

所有在模板test和check所确定的范围内的行都被打印:

sed -n '/test/,/check/p' file
1

打印从第5行开始到第一个包含以test开始的行之间的所有行:

sed -n '5,/^test/p' file
1

对于模板test和west之间的行,每行的末尾用字符串aaa bbb替换:

sed '/test/,/west/s/$/aaa bbb/' file
1

# 多点编辑:e命令

-e选项允许在同一行里执行多条命令:

sed -e '1,5d' -e 's/test/check/' file
1

上面sed表达式的第一条命令删除1至5行,第二条命令用check替换test。命令的执行顺序对结果有影响。如果两个命令都是替换命令,那么第一个替换命令将影响第二个替换命令的结果。

和 -e 等价的命令是 --expression:

sed --expression='s/test/check/' --expression='/love/d' file
1

# 从文件读入:r命令

file里的内容被读进来,显示在与test匹配的行后面,如果匹配多行,则file的内容将显示在所有匹配行的下面:

sed '/test/r file' filename
1

# 写入文件:w命令

在example中所有包含test的行都被写入file里:

sed -n '/test/w file' example
1

# 追加(行下):a\命令

将 this is a test line 追加到 以test 开头的行后面:

sed '/^test/a\this is a test line' file
1

在 test.conf 文件第2行之后插入 this is a test line:

sed -i '2a\this is a test line' test.conf
1

# 插入(行上):i\命令

将 this is a test line 追加到以test开头的行前面:

sed '/^test/i\this is a test line' file
1

在test.conf文件第5行之前插入this is a test line:

sed -i '5i\this is a test line' test.conf
1

# 下一个:n命令

如果test被匹配,则移动到匹配行的下一行,替换这一行的aa,变为bb,并打印该行,然后继续:

sed '/test/{ n; s/aa/bb/; }' file
1

# 变形:y命令

把1~10行内所有abcde转变为大写,注意,正则表达式元字符不能使用这个命令:

sed '1,10y/abcde/ABCDE/' file
1

# 退出:q命令

打印完第10行后,退出sed

sed '10q' file
1

# 保持和获取:h命令和G命令

在sed处理文件的时候,每一行都被保存在一个叫模式空间的临时缓冲区中,除非行被删除或者输出被取消,否则所有被处理的行都将 打印在屏幕上。接着模式空间被清空,并存入新的一行等待处理。

sed -e '/test/h' -e '$G' file
1

在这个例子里,匹配test的行被找到后,将存入模式空间,h命令将其复制并存入一个称为保持缓存区的特殊缓冲区内。第二条语句的意思是,当到达最后一行后,G命令取出保持缓冲区的行,然后把它放回模式空间中,且追加到现在已经存在于模式空间中的行的末尾。在这个例子中就是追加到最后一行。简单来说,任何包含test的行都被复制并追加到该文件的末尾。

# 保持和互换:h命令和x命令

互换模式空间和保持缓冲区的内容。也就是把包含test与check的行互换:

sed -e '/test/h' -e '/check/x' file
1

# 脚本scriptfile

sed脚本是一个sed的命令清单,启动Sed时以-f选项引导脚本文件名。Sed对于脚本中输入的命令非常挑剔,在命令的末尾不能有任何空白或文本,如果在一行中有多个命令,要用分号分隔。以#开头的行为注释行,且不能跨行。

sed [options] -f scriptfile file(s)
1

# 打印奇数行或偶数行

方法1:

sed -n 'p;n' test.txt  #奇数行
sed -n 'n;p' test.txt  #偶数行
1
2

方法2:

sed -n '1~2p' test.txt  #奇数行
sed -n '2~2p' test.txt  #偶数行
1
2

# 打印匹配字符串的下一行

grep -A 1 SCC URFILE
sed -n '/SCC/{n;p}' URFILE
awk '/SCC/{getline; print}' URFILE
1
2
3
shell编程
Zookeeper

← shell编程 Zookeeper→

最近更新
01
postgresql安装
06-24
02
oracle笔记
06-24
03
opengauss笔记
06-24
更多文章>
Theme by Vdoing | Copyright © 2019-2025 kevin | 小诺运维
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×