Sed, awk 都可以 -f scriptfile inutfile
元字符 . 匹配除换行符以外的任意单个字符,在awk句点也能匹配换行符
元字符 * 匹配任意一个包括零个在它前面的字符 这个*理解很重要,任意一个指的是一 个或者多个也可以没有
举列:
yexiang@ubuntu:<~>$ cat test1.txt
yexiang,hello world .
I am a new student.
m
my name is yexiang
yexiang@ubuntu:<~>$ grep "m*" test1.txt
yexiang,hello world .
I am a new student.
m
my name is yexiang
这里 m* 把所有的行都打印出来了,那是因为我可以匹配到m 行也可以匹配不到m行(0个),
yexiang@ubuntu:<~>$ grep "m." test1.txt
I am a new student.
my name is yexiang
这里并没有打印出 m 单独的行,因为 m. 是指的必须要2个字符
[...] 匹配方括号中的字符类的任意一个。如果方括号中的第一个字符为脱字符(^),则表示否定匹配,既匹配除了换行符和类中列出的那些字符以外的所有字符。Awk中可匹配换行符,连字符(-) 用于表示字符的范围,如果类中的第一个字符为右括号( ] ), 则表示它是类的成员,所有其他的元字符在被指定为类中成员时都会失去它们原来的含义
^ 如果作为正则表达式的第一个字符,则表示匹配行的开始,在awk中匹配字符串的开始,即使字符串包含嵌入的换行符
$ 如果作为正则表达式的最后一个字符,则表示匹配行的结尾,在awk中匹配字符串的结尾,即使字符串中包含嵌入的换行符。
\{n,m\} 匹配它前面某个范围内单个字符出现的次数,\{n\} 将匹配n次出现,\{n,\} 至少匹配n次出现,\{n,m\} 匹配n和m之间的任意次出现。
\ 转义随后的字符
扩展的元字符:(egrep, awk)
+ 匹配前面的正则表达式的一次或多次出现
?匹配前面的正则表达式的零次或一次出现
| 指定可以匹配其前面的或者后面的正则表达式
() 对正则表达式分组
{n,m} 匹配它前面某个范围内单个字符出现的次数,{n} 将匹配n次出现,{n,} 至少匹配n次出现,{n,m} 匹配n和m之间的任意次出现。
字符类[ ]中的特殊字符:
\ 转义任意特殊字符
- 当它不在第一个或者最后一个位置的时候,表示一个范围
^ 仅当第一个位置的时候表示反转匹配
如果指定多个连续的字符,可以使用多个字符类。
[ ][ ][ ]...
如果为了匹配运算操作符,那么可以把 - 号放在开头或者结尾让其失去特殊的意义
[-+*/]
使用 .* 匹配的范围总是最大,因为匹配任意字符的零次或者多次出现
2个定位元字符 ^, $
可以一起使用 ^$来匹配空行
^.*$ 匹配整个行
词首定位符 \< 如:/\<love/
词尾定位符 \> 如:/love\>/
指定跨度元字符 \{n,m\} , n m 是0-255之间的整数。
{n} 将匹配n次出现,
{n,} 至少匹配n次出现,
{n,m} 匹配n和m之间的任意次出现。
? 等价于 \{0,1\}
* 等价于 \{0,\}
+ 等价于 \{1,\}
举例:
[0-9]\{3\}-[0-9]\{2\}-[0-9]\{4\} 可以匹配类似这样的电话号码 xxx-xx-xxxx
选择性元字符 |
分组元字符 ()
可使用 | () 来对选择性进行分组
如: compan(y|ies) 单数或者复数匹配
SED
Sed 维护一种模式空间,既一个工作区或临时缓冲区,当应用编辑命令时将在那里存储单个输入行。一次一行的设计是一个sed的优点,在读取庞大的文件时不会出错
/s/CA/California/g 替换 CA 为 California
/yexiang/s/CA/California/g 只替换包含了yexiang 的行 才将 CA 替换为 California
上面的相当于向前提供了地址。
1. 如果没有提供地址,那么命令将用于每一行
2. 如果只有一个地址,那么命令将应用于与这个地址匹配的每一行
3. 如果指定了由逗号分隔的两个地址,那么命令应用于匹配第一个地址的第一行和它后面的行,直到匹配第二个地址的行(包括此行)
4. 如果地址后面跟有感叹号,那么命令就应该用于不匹配该地址的所有行
d 删除所有行
1d 删除第一行
$d 删除输入的最后一行
当正则表达式作为地址提供时,这个命令只影响与这个模式匹配的行,必须封闭在/ 中,如: /^$/d 只删除空行,其他行不变
/^\.TS/,/^\.TE/d 它删除了从第一种模式匹配的行开始,到由第二种模式匹配的行(包括此行在内)为止的所有行
50,$d 删除50行开始到最后一行的所有行
行地址和模式地址混合使用:
1,/^$/d 删除第一行开始到第一个空行的所有行。 由于sed没办法决定第二个地址是否会匹配,所以如果没有空行,那么它将删除所有的行。
/^\.TS/,/^\.TE/!d 感叹号会反转匹配的意义,下面的脚本将删除在两种匹配的以外的所有行
sed分组 用大括号 {} 将一个地址嵌套在另一个地址中。或者在相同的地址上应用多个命令。
/^\.TS/,/^\.TE/{
/^$/d
}
左大括号必须在行末,右大括号本身必须单独占一行,确保在大括号后没有空格。
可使用大括号编辑命令括起来对某个范围的行应用多个命令
/^\.TS/,/^\.TE/{
/^$/d
s/^\.ps 10/.ps 8/
s/^\.vs 12/.vs 10/
}
上面的格式是:
Address {
Command 1
Command 2
Command 3
}
sed -f scriptfile inputfile
sed 不会改变原始文件,除非重定向到输入文件,一般输出到屏幕上
为了保持修改可以保持到另外文件中去
sed -f scriptfile inputfile > outputfile
diff inputfile outputfile
Inputfile 会显示 <
Outputfile 会显示 >
Address {
Command 1
Command 2
Command 3
}
每个命令都可以有自己的地址并允许有多层分组
在命令后添加空格会产生语法错误,因为命令的结束必须在行末尾处
特殊: 命令直接可以用分号放在同一行上 command1;command2,但不提倡
注释:
第一个字符必须是#号,可以使用反斜杠来结束前面的行使得注释可以继续多行。
如果跟在 #号后面的是字符n ,#n 那么脚本不会自动产生输出 这个指令 -n 是等价的
替换:
[address]s/pattern/replacement/flags
这里修饰替换的标志flags是:
n:1到512之间的数字,表示对文本模式中指定模式第n次出现的情况进行替换
g: 对模式空间中所有出现的情况进行全局更改,没有g通常只有第一次出现情况
p: 打印模式空间内容
W file 将模式空间的内容写到文件file中。
如果没有指定地址,那么就应用于pattern 匹配的所有行,如果正则表达式来提供地址,并且没有指定模式,那么替换命令匹配由地址匹配的内容,
如果模式中包含了斜杠\, 那么可以选择另外一个字符作为限定符。如感叹号:
s!/usr/mail!/usr2/mail!
Flags可以进行组合使用 如 gp
Replacement 是一个字符串。在replacement 匹配的部分,只用下列字符有特殊含义:
& 用正则表达式匹配的内容进行替换
\n 匹配第n个字串,这个字串以前在pattern中用 \( 和 \) 指定
\ 当替换部分包含&,\,和替换命令的定界符时候可以用\转义它们
s/./>/2 用>替换第二个 .
如果一行中有3个. 那么默认替换只替换第一个. 所以默认的数字是1
替换元字符:
反斜杠\, &, \n ,反斜杠一般用于转义其他元字符,但是它在替换字符串中也用于包含换行符
s/./\
/2
这样是用换行符替换第二个. 换行符后面不能有空格
s/ORA/O`Reilly \& Associates\g 转义&符号
如果 没有加 \ 转换& 符号,上面的输出为 O`Reilly ORA Associates ,用正则表达式匹配的内容进行替换
上面的&符号是替换的固定的单词,也可以替换一个模式匹配的内容如:
s/See Section [1-9][0-9]*\.[1-9][0-9]*/(&)/ 如果是匹配到 See Section 1.4 结果为
(See Section 1.4)
sed 中转义的圆括号括住正则表达式任意部分并且保存它以备回调,一行最多允许保存9次, \n,n是1-9数字。
s/\(See Section \) \([1-9][0-9]*\.[1-9][0-9]*\)/\1\\fB\2\\fP/
这里的\1 回调 See Section
这里的\2 回调 [1-9][0-9]*\.[1-9][0-9]
再举例: 交换
First :Second
sed ‘s/\(.*\):\(.*\)/\2:\1/’
结果
Second :First
删除:
/^$/d 删除空行
追加插入和更改
追加 [line-address]a\
text
插入 [line-address]i\
text
更改 [address]c\
text
插入命令是在模式空间当前行之前
追加命令是在模式空间当前行之后
更改命令是取代模式空间的内容
这些命令的每一个都要求后面跟一个\反斜杠用于转义第一个行尾。Text必须从下一行开始
要输入多行文本,每个连续的行都必须用反斜杠结束。最后一行列外
/<Larry`s Address>/i\
4700 Cross Court \
French Lick,IN
如果文本中有一个字面的 \,那么要添加一个\进行转义
追加和插入命令只能用于一行,更改命令可以用于多行
列表:
列表命令 l 用于显示模式空间的内容,将非打印的字符显示为两个数字的ASCII代码,
转换:
[address]y/abc/xyz/ 该行上的 a都被转换为x,不管a后面是否跟了b
这个功能在转换大小写有用
打印:
打印命令P , #n 相当于 -n抑制了打印
打印行号:
[line-address] =
下一步 next 命令 (n) 输出模式空间的内容,然后读取下一行
[address]n
/^\.H1/{
n
/^$/d
} 这个删除.H1 之后的空行
读和写命令: 直接作用于文件本身
[line-address]r file
[line-address]w file
退出:
退出命令 q会使sed停止读取新的输入行。它的语法为
[line-address]q,它只适用于单行,如果找到了匹配的行就立刻停止
sed ‘100q’test // 打印100行退出,有点类似head命令
高级sed命令
1. 多行空间模式:(N,D,P)对应于单行模式的 (n,d,p)
2. 采用保持空间来保存模式空间的内容并使它可用于后续的命令(H,h,G,g,x)
3. 编写使用分支和条件指令的脚本来更改控制流程(:、b、t)
D :删除多行模式空间的第一行,
d : 删除模式空间的内容
N: 读取新的输入行,并将它添加到模式空间的现有内容之后来创建多行模式空间,模式空间最初的内容和新的输入行之间用换行符分隔,在模式空间中嵌入的换行符可以利用转义序列’\n’来匹配,多行模式空间中,元字符^匹配空间中第一个字条,而不匹配换行符后面的字符,$只匹配模式空间中最后的换行符,而不匹配任何嵌入的换行符,
n : 输出模式空间的内容,然后读取新的输入行。
P :多行打印输出多行模式空间的第一部分。直到第一个嵌入的换行符
模式空间是容纳当前输入行的缓冲区,还有一个称为保持空间的顶留缓冲区。
模式空间内容可以复制到保持空间,保持空间也可以复制到模式空间。
保持空间最常用的用途是:
当改变模式空间中的原始内容时,用于保留当前输入行的副本。
H或 h,将模式空间的内容复制或追加到保持空间
G 或 g, 将保持空间的内容复制或追加到模式空间
x 交换保持空间和模式空间的内容
小写命令复制缓冲区内容,大写命令追加缓冲区内容
分支(b) 和测试 (t) ,分支是无条件转移,测试是有条件转移
标签:是任意不多于7个字符的序列
:mylabel
b mylabel
[address]b[label] 将控制转移到另一行上
如果没有给出label,控制就转移到脚本的结尾处
如果当前匹配地址上进行了成功的替换,那么t命令就会转移标签或者结尾处
[address]t[label]
AWK
awk是一个非常棒的数字处理工具。相比于sed常常作用于一整行的处理,awk则比较倾向于将一行分为数个“字段”来处理。运行效率高,而且代码简单,对格式化的文本处理能力超强
awk的一般语法格式为:
awk [-参数 变量] 'BEGIN{初始化}条件类型1{动作1}条件类型2{动作2}。。。。END{后处理}'
其中:BEGIN和END中的语句分别在开始读取文件(in_file)之前和读取完文件之后发挥作用,可以理解为初始化和扫尾。
-v var=$v 把v值赋值给var,如果有多个变量要赋值,那么就写多个-v,每个变量赋值对应一个-v
e.g. 要打印文件a的第num行到num+num1行之间的行,
awk -v num=$num -v num1=$num1 'NR==num,NR==num+num1{print}' a
awk ‘{print “Hello world”}’ file
awk ‘BEGIN {print “Hello world”}’
如果忽略了文件名,那么awk期望得到来自键盘的输入。
awk -f script file
awk 可以在任何地方进行注释。以#开头,换行符结尾
如果以命令行的方式提供awk程序,而不是将它写入一个文件中,那么程序的任何地方都不能用单引号,否则shell将对它进行解释而导致错误
用来分隔字段的字符被称为分隔符。一般为空格或者制表符
awk 允许使用字段操作符 $来指定字段。在该操作符后面跟着一个数字或者变量用于标识字段的位置。$1 标识第一个字段,$2 标识第二个字段,$0 表示整个输入的记录
ls -al | awk '{print $1}'
ls -al | awk '{print $3,$4}'
可以用任何计算值为整数的表达式表示一个字段。
echo a b c d | awk ‘BEGIN { one=1;two=2} {print $(one+two)}’ 输出c
可以在命令行中使用 -F 选项来改变字段的分隔符。后面跟着分隔符
如 : awk -F”\t”
在脚本中指定分隔符是一个好的习惯。因为这个是必须在读取第一行输入的时候之前执行,所以必须在由BEGIN 规则控制的操作中指定这个变量
BEGIN {FS = “,”}
分隔符默认是空白字符,可以设置单个字符,也可以设置为正则表达式,字段分隔符将是与正则表达式匹配的“最左边最长的非空的不重叠的 子串” 如:
1. FS = “\t”
2. FS = “\t+”
如果用于 abc\t\tdef ,第一种将分隔3个字段,中间一个为空字段, 如果是第二种将分隔2个字段,
3. FS = “[’:\t]” 这3个字符的任意一个字符都可以被解释为字段分隔符
awk ‘{print “ ”}’ 空字符会打印换行
测试匹配指定的字段: ~ 操作符 , !~ 和 ~ 相反
常量有2种类型:字符串类型或数字类型 “red”,1 。字符串必须用引号括起来
转义字符:
\r 回车
\t 水平制表符
\v 垂直制表符
\ddd 将字符表示为1-3位的八进制
\xdex 将字符表示为十六进制
\c 任何需要字面表示的字符 ,例如 “for”
操作符有 +,-,*,/,% ,^, **,-=,+=,*= ,/= , ++,-- , < , > , <= , >= , == , != , ~ ,!~
|| ,&& , !
/^$/{
Print x+=1
} // 碰到一个空行就打印 x值
/^$/{
++x
}
END{
print x
} // 读完最后一个空行的时候再打印x值
系统变量:
NF : 定义了当前输入记录中的字段个数
如:cat b为
1:2:3
4:5:6
awk -F ':' '{print NF}' b的输出为
3
3
NR 已经读出的记录数
awk -F ':' '{print NF}END{print NR}' b
3
3
2
FS: 输入字段分隔符(缺省为:space:),相当于-F选项
awk -F ':' '{print}' a 和 awk 'BEGIN{FS=":"}{print}' a 是一样的
RS:输入记录分隔符,缺省为"\n"
合理的使用RS和FS可以使得awk处理更多模式的文档,例如可以一次处理多行
例如,如果文件c,cat c为
hello_world; I_want_to_go_swimming_tomorrow;ha_ha
运行 awk 'BEGIN{ RS = ";" } {print $1}' c 的结果为
hello_world
I_want_to_go_swimming_tomorrow
ha_ha
因为默认 FS为空格,所以上面打印是正确的,并没有分隔
如果运行 awk 'BEGIN{ FS=”_”;RS = ";" } {print $1}' c 的结果为
hello
I
ha
OFS输出字段分隔符(缺省为:space:)
以c文件为例
如果运行 awk 'BEGIN{ FS=”_”;RS=";";OFS=”.”} {print $1,$2}' c 的结果为
hello.world
I.want
ha.ha
ORS:输出记录分隔符,缺省为换行符,控制每个print语句后的输出符号
当 awk 'BEGIN{ FS=”_”;RS=";";OFS=”.”; ORS = "_"} {print $1,$2}' c 的结果为
hello.world_I.want_ha.ha_
FNR 当前文件的记录数 一般来说和 NR一样
格式化打印:
print 提供了自动换行
printf 不提供自动换行
printf 格式化说明:和C语言基本一样
c ASCII字符
d 十进制整数
s 字符串
u 无符号十进制
x 无符号十六进制小写
X 无符号十六进制大写
- 进行左对齐,默认右对齐
如: printf(“%d\t%d\n”,$5,$9)
printf 语句输出的默认精度可以通过设置系统变量OFMT来改变。
向脚本传递参数:
变量可以在命令行上设置,在脚本的后面,文件的前面
awk -f scriptfile var=vaule inputfile ,等号的两边不允许出现空格
命令行中: awk -f xxx high=100 low=60 file
脚本中可以: awk -f xxx “high=$1” “low=$2” file
环境变量或命令的输出结果也可以作为变量的值来传递。
如:
awk xxx dir=$cwd file
awk xxx dir=’pwd’ file // 反引号
所以可以使用命令行参数定义系统变量,如 FS, NR 等
命令行参数的一个重要限制就是在BEGIN过程中不可用。
POSIX awk 提供了一个解决方法,就是在脚本前 使用 -v 选项 ,那么BEGIN过程就能得到
If (experssion) action1
else action2
或
If(expression) action1; else action2
条件操作符: expr ? action1: action2
循环: while,do,for
While(condition)
action
do
action
while(condition)
For(xxx;xxx;xxx)
循环中可以用continue到循环的顶部,break退出循环,还有另外2个语句可以控制
next 语句能够导致读入下一个输入行,并返回脚本的底部。Next语句的典型应用是可以连续的从文件读取内容,忽略脚本的其他操作直到文件读完。系统变量FILENAME提供了当前文件的名字,可以编写模式:
FILENAME==”acronyms”{
action
next
}
这使得对文件acronyms的每行都执行action指定操作。完成操作后输入下一个新行。
exit 语句使主输入退出循环并将控制移动到END规则。如果END存在的话。如果没有定义END规则,或在END中应用exit语句,则终止脚本。可以使用一个表达式作为参数。 该表达式将作为awk的退出状态码。如果没有提供表达式,那么返回0。如果exit语句设置了一个初始值。然后在END中再次调用没有参数的exit,则使用第一个值。
awk ‘{
.....
exit 5
}
END{exit}’ // 状态码是5
数组: awk中不必为数组指定大小。只需要指定标识符。
在awk中所有的数组都是关联数组。关联数组的独特之处在于它的下标可以是字符或一个数值。顺序不一定有序。但是对于数值型下标也能够顺序访问数值中的所有元素。
array[$1]=$2
array[“BASIC”] = “Instruction Code”
特殊的for循环访问关联数组所有元素
for(var in array)
array[var]
这个语法可以应用于数值型下标数组,但是数组中的条目顺序是随机的。
关联数组awk中所有数字的下标都是字符串类型。即使使用数字作为下标,awk 将自动把它们转为字符串。
关键字 in 也是一个操作符。用在条件表达式中测试一个下标是否是数组的成员。
Item in array
If(“BASIC” in acro)
内置函数split 能够将任何字符串分解到数组的元素中。这个函数对于从字段中提取“子字段”很有用。
n = split(string,array,separator)
如果没有指定分隔符separator,那么将使用分隔符 FS。
删除数组元素:
delete array[xxx]
Awk 支持线性数组,不支持多维数组,但是可以提供下标模拟多维数组
File_array[NR,i] 表示第NR个记录的第i个字段
If((i,j) in array)
系统变量数组:
ARGC 命令行参数的个数
ARGV 命令行参数数组
ARGIND 当前被处理文件的ARGV标志符
数组ARGV中下标从0开始,最后一个是ARGC-1, 第1个数组是调用的程序名或者文件名
ENVIRON 环境变量数组
函数:
算术函数:
cos(x), exp(x),int(x),log(x),sin(x),rand(),srand(x)
Rand()生成一个0-1之间的浮点数伪随机数
字符串函数:
gsub(r,s,t)
字符串t中用字符串s替换和正则表达式r匹配的所有字符串,返回替换的个数,如果没有给出t默认为$0
index(s,t)
返回子串t在字符串s中位置,如果没有指定s,则返回0
length(s)
返回字符串s的长度,如果没有给出s,返回$0的长度
match(s,r)
如果正则表达式r在s中出现,则返回出现的起始位置,如果在在s中没发现r,则返回0,设置RSTART和RLENGTH的值, RSTART记录的是匹配子串的开始位置。RLENGTH记录的匹配字符串的字符数。不匹配时候 RSTART=0, RLENGTH=-1
split(s,a,sep)
使用字段分隔符sep将字符串s分解到数组a的元素中,返回元素的个数,如果没有给出sep,则使用FS
sprintf(“fmt”,expr)
对expr使用printf格式说明
sub(r,s,t)
在字符串t中用s替换正则表达式r的首次匹配,如果成功则返回1,否则返回0,如果没有给出t,默认为$0
substr(s,p,n)
返回字符串s中从位置p开始最大长度为n的子串,如果没有给出n,返回从p开始剩余的字符串
tolower(s)
将字符串s中的所有大写字符转换为小写,并返回新串。
toupper(s)
将字符串s中的所有小写字符转换为大写,并返回新串。
gsub(r,s)
可以实现输入字符串中所有位置的替换
自定义函数:
function xxx(xxx,xxx, 局部变量,局部变量){
}
参数一般是传值,数组是引用
如果把多个函数保存在多个文件中,awk允许使用多个-f 选项来指定多个程序文件。
awk -f xxx -f xxxx
getline 函数
调用只能写成 getline 不用加()
getline和 next 类似, next 读取下一行并将控制传递给脚本的顶部,但是getline读取之后并没有改变脚本的控制
返回:
1 . 如果能够读到一行
0. 如果到了文件结尾
-1. 如果遇到了错误
从文件中读取:
getline < “filename”
while((getline < “filename”) > 0)
将输入赋给一个变量:
getline input
从管道读取输入:
“who am i”| getline
Close()函数用于关闭打开的文件和管道,原因有几个,第一,每次你只能打开一定数量的管道。你必须用close() 来关闭一个你用过的管道。通常是当getline返会0,-1,如:close(“who”)
system函数执行一个以表达式给出的命令。
如: system(“mkdir tt”)
直接向文件或管道输出:
print , printf > “filename” , >> “filename”
print, printf | command 如: print | “wc -w”
使用#!语法调用awk
#!/bin/awk -f
或
#!/bin/sh
/bin/awk ‘{printf x}’
如果使用了 #!/bin/awk -f ,那么当执行 myscript filename 相当于
/bin/awk -f myscript filename
BEGING .END 可以多次出现,执行顺序安装他们定义的顺序