sed与awk

ftp://ftp.oreilly.com/published/oreilly/nutshell/sedawk_2

 有3种方法能够在命令行上放多个指令:html

1. 用分号分隔指令
sed 's/ma/, mutil/;s/zhao/zzzz/'
2, 使用-e
sed -e 's/fs/fsgf/' -e 's/dfdg/dhs/'
3. 使用分行指令功能
    sed '
s/g/dfgh/
s/zz/dfgf/
s/CA/,FG/' list

4. sed / awk -f scriptfile file

sed和awk指令结构相同,都是由模式和过程组成,而且都可使用多个指令。在awk中语句和函数取代了一个或两个字符组成的命令序列,例如print语句打印输出。linux

 awk出错信息git

1. 没有用大括号{},将动做括起来。
2. 没有用单引号' '将指令括起来。
3. 没有用斜杠//将正则括起来。

 awk引用外部变量http://www.xuebuyuan.com/105422.html正则表达式

awk在使用某个变量前没必要先赋值,由于awk将变量复制为空字符串。shell

正则相关编程

1. 在awk中点号.能够匹配换行。
2. [...]方括号中^表示取反,即取其余字符,awk中包括换行。第一个字符为右括号]或-时表示它是成员,同事存在时]放第一个,-放最后。其余元字符在方括号中失去原来的含义,反斜杠\在awk的方括号中仍有特殊意义,能够转义连字符或方括号,如[a\]1]。
3. {n,m}在有些awk中仍然不能使用。awk支持egrep中的大多数正则用法。扩展正则:+, *, |, (), {},
4. .[!?;:,".] . 第一个和最后一个点是通配。
5.
POSIX字符类及意义:  必须出如今方括号表达式中,如[[:upper:]]
[:upper:]  表示大写字母[A~Z]
[:lower:]  表示小写字母[a~z]
[:digit:]  表示阿拉伯数字[0~9]
[:alnum:]  表示大小写字母和阿拉伯数字[A~Za~z0~9]
[:space:]  表示任何产生空白的字符,包括空格或Tab键等
[:alpha:]  表示大小写字母[A~Za~z]
[:cntrl:]  表示键盘的控制按键,包括Tab、Del等按键
[:graph:]  表示除了空格符(空格键与Tab键)外的其余全部按键
[:print:]  表示任何能够被打印出来的字符
[:xdigit:] 表示十六进制数字[0~9A~Za~z]
[:blank:]  表示空格键与Tab键
[:punct:]  表示标点符号,包括:" ' ? ! ; : # $... 
基本sed命令
sed命令能够指定0个,1个,或2个地址。每一个地址都是一个描述模式,行号或者正则表达式。 注: 行号计数器不会由于多个输入文件重置。 若是指定了逗号分隔的两个地址,那么命令应用于第一个地址的第一行和它后面的行,直到匹配第二个地址的行(包括此行)。第二个地址从第一个地址以后开始寻找。第一个地址启用动做,第二个地址禁用动做,没法先行决定第二个地址是否会匹配,一旦匹配了第一个地址,这个动做就应用与这些行。直至第二个地址匹配。 若是地址后有感叹号
!,那么命令将应用与不匹配该地址的全部行。 /^\.TS/,/^\.Te/!d 删除这些行以外的全部行。

$能够表示最后一行,但不该该和正则表达式中的$混淆。正则必须封闭在斜杠(/)中。 /^$/d

命令后添加空格会产生语法错误,命令的结束必须在行的结尾处。
若是命令之间用分号分隔,那么能够讲多个sed命令放在同一行。 n;d在结构上是正确的,而后在n后面放置一个空格会致使语法错误,而在d前面放置一个空格是能够的。不提倡在同一行放置多个命令。
分组命令
linux sed命令详解 http://www.cnblogs.com/ggjucheng/archive/2013/01/13/2856901.html
http://www.cnblogs.com/stephen-liu74/archive/2011/11/17/2245130.html
sed使用大括号{}将一个地址嵌套在另外一个地址中,或者在相同的地址上引用多个命令。 若是想指定行的范围,而后再这个范围内再指定另外一个地址,则能够嵌套地址。注:左大括号必须在行末,并且右大括号自己必须单独占一行。要确保在大括号以后没有空格。
/^\.TS/,/^\.Te/{          注:大括号能够在同一行上,命令之间用分号隔开。sed -n '/root/{n;d}' /etc/passwd #将匹配root行的下一行删除
/^$/d  #命令在大括号内能够缩进
s/zhaodfd/.ps 8/
s/^\.vs 2/.ps 10/  #替换部分的点号没必要转义。
}
替换
[address]s/pattern/replacement/flags
flags能够是:n(第n次), g, p, W file(写入文件)
分隔符能够是任意字符,出现3次而且在replacement以后是必须的。s!/home/z!/home/x!
在replacement部分只有下列字符有特殊含义:
&:正则匹配的整个内容
\n : 第n个字符串,在pattern中用\(。。。\)指定。
\ :转义字符。&符号,反斜杠\,定界字符,换行均可以用\转义。所以除了正则中的元字符外,sed的替换部分也有元字符。
echo 'zh xng' | sed 's/ /\    #转义换行,\&    注: 上换行用\n也能够
xxxxxxxx\      #换行
yyyyyyyyyy/'
注: 若是匹配同一行的多个替换命令,那么该行的多个备份就会被打印或者写到文件中。
删除
d,删除整行,而不是匹配部分。一旦执行删除命令,那么在“空的”模式空间中就不会再有命令执行。删除命令会致使读取新的输入行,而编辑脚本则从头开始新的一轮(这一行为和next命令相同),UNIX文件写到:不容许在被删除的行上进一步操做。
追加,插入,更改
[line-address]a\, [line-address]i\, [address]c\. 命令后面接反斜杠或者空格均可以。可是用反斜杠才是正路,不少书籍和命令详解都用的是反斜杠。
[root@tg output]# echo -e 'zhao xiang dsgf fsad  ssdf sdgfdfsgd' | sed '/zhao/a\ ni hao'  
#斜杠后面的任何内容追加在匹配行以后,即便是命令 /xian/i\ first line也被当作文本。空格也原样追加。
[root@tg output]# echo -e 'zhao xiang dsgf fsad ssdf sdgfdfsgd' | sed '/zhao/a\ ni hao' zhao xiang dsgf fsad ssdf sdgfdfsgd ni hao [root@tg output]# echo -e 'zhao xiang dsgf fsad ssdf sdgfdfsgd' | sed '/zhao/a ni hao' #若是命令后面接空格,则多余的空格被忽略了。 zhao xiang dsgf fsad ssdf sdgfdfsgd ni hao
正确的作法应该是在命令后用反斜杠,而后追加的文本单独起一行,文本中有换行用\n或者用反斜杠换行。最后一行不用反斜杠。 这样即便有多个命令也不会有问题。
[root@tg output]# echo 'test  zhao xiang ' | sed '/^test/a\
--->this is a example
> /xiang/i\
> first line'
first line
test  zhao xiang 
--->this is a example
[root@tg output]# 
[root@tg output]# echo 'test  zhao xiang ' | sed '/^test/i\
> '

test  zhao xiang 
[root@tg output]#插入空行,让命令后面的行为空
更改命令清除模式空间,与删除命令有一样的效果,在更改命令以后的命令不该该被提供。
插入和追加命令不影响模式空间的内容。所提供的文本将不匹配后续命令的任何地址,那些命令也不影响该文本,无论什么更改改变了模式空间,所提供的文本仍然会正确输出。即便模式空间不是那样的,并且,所提供的文本不参与sed的内部计数器

 列表命令数组

列表命令l 用于显示模式空间的内容,并将非打印字符显示为两个数字的ASCII码。相似于vi的列表命令(:l)dom

sed -n -e "l" test
由于列表命令当即产生输出,因此抑制默认的输出,不然会获得行的重复。

 转换函数

[address]y/abc/xyz/ 影响模式空间的全部内容post

打印行号

[line-address]= , 这个命令不能对一个范围的行进行操做。

下一步

[address]n , 输出模式空间的内容(若是没有抑制输出)而后读取下一行,替换模式空间,而不返回到脚本的顶端,以前的命令应用于当前行,后续命令应用于替换以后的内容。

读和写

[line-address]r file, [address]w file . 读命令将由fiel指定的文件肯定的行以后的内容读入模式空间,不能对行范围操做。写命令将模式空间的内容写入文件。文件名以前必须有空格,空格后到换行符前的内容都是文件名。 文件不存在也不会报错。若是一个脚本有多个命令写到同一个文件中,那么每一个命令的内容将追加到文件中。并且每一个脚本最多只能打开十个文件。

使用-n能够阻止模式空间的行被自动输出,可是读命令的结果仍然转到标准输出。

退出

退出命令[line-address]q, 会使sed中止读取新的输入行,并中止将他们送到标准输出。它只适用于单行地址,一旦找到匹配行,脚本就结束。

 

awk

 echo a b c | awk 'BEGIN {one = 1;two=2} {print $(one+two)}'  #输出c

 分隔符:

awk -F"\t" 或者 BEGIN{ FS=","} ,可使用正则。 输出分隔,OFS="\t",OFS能够从新定义为一系列字符。

print $1,$2  逗号使个字段之间用空格隔开。不用逗号则各字段连在一块儿,print $1 "," $2  ,输出"$1逗号$2"。 输出域的分隔符默认是一个空格,保存在OFS中。如$ awk -F: '{print $1,$5}' test,$1和$5间的逗号就是OFS的值。

awk中RS,ORS,FS,OFS区别与联系

变量

awk中可使用转义序列。变量,运算符,表达式,控制结构和C类似。变量无需加$符号,未初始化的变量为空或0。  每一个变量有字符型值和数值型值,不包含数字的字符串为0.

空格是字符串链接操做符。Z="hello" "world"

赋值操做符:++,--,[+-*/%^]= ,**=  ,关系操做符:>,<,>=,<=,==,!=, ~, !~ 匹配/不匹配。逻辑操做&&,||,! ,!能够用于字符串,判断字符串是否非空。 见awk编程: 复合表达式,都和C相似。 匹配能够用于字符串变量也可用于/regex/. name=root; $1 ~ name 或者 $1 ~ /root/  貌似用正则的地方也能够用字符串。

in操做符能够判断某个下标是否在数组中。条件操做 expr ? action1 : action2

改变当前记录的字段数NF的值会有反作用,增长NF的值会建立新的空字段,并从新创建$0,字段由OFS的值分隔。

变量名    变量内容
ARGC    命令行参数的数量。
ARGIND    命令行正在处理的当前文件的AGV的索引。
ARGV    命令行参数数组。
CONVFMT    转换数字格式。
ENVIRON    从shell中传递来的包含当前环境变量的数组。
ERRNO    当使用close函数或者经过getline函数读取的时候,发生的从新定向错误的描述信息就保存在这个变量中。
FIELDWIDTHS    在对记录进行固定域宽的分割时,能够替代FS的分隔符的列表。
FILENAME  当前的输入文件名。
FNR    当前文件的记录号。
FS    输入分隔符,默认是空格。
IGNORECASE    在正则表达式和字符串操做中关闭大小写敏感。
NF    当前文件域的数量。
NR    当前文件记录数。
OFMT    数字输出格式。
OFS    输出域分隔符。
ORS    输出记录分隔符。
RLENGTH    经过match函数匹配的字符串的长度。
RS    输入记录分隔符。
RSTART    经过match函数匹配的字符串的偏移量。
SUBSEP    下标分隔符。
[zhangy@localhost test]$ awk 'BEGIN{OFS="|";}{print $1,$2}' test1
 111|222
 333|444
 555|666
[zhangy@localhost test]$ awk 'BEGIN{OFS="|";}{print $1 OFS $2}' test1
 111|222
 333|444
 555|666
[zhangy@localhost test]$ awk 'BEGIN{OFS="|";}{print $0}' test1
 111 222
 333 444
 555 666
[zhangy@localhost test]$ awk 'BEGIN{OFS="|";}{NF=NF;print $0}' test1
 111|222
 333|444
 555|666
为何第二种方法中的OFS生效呢?我的以为,awk觉查到列有所变化时,就会让OFS生效,没变化直接输出了。 能够设置$1=$1

能够用NF来引用最后一个字段。 $NF,$(2+3)

多行记录

FS="\n"; RS="" 记录分隔符为空字符串,表明空行。 

OFS="\n"; ORS="\n\n"; 

格式化打印 

printf(format,[args]) , 圆括号可选。 Shell经常使用技巧(五) awk编程 , Awk学习笔记 ,Shell编程-awk

format的格式:%-width.precision specifier , 数值的默认precision为"%.6g" ,默认精度能够经过设置系统变量OFMT来改变,如"%.2f"。

向脚本传递参数

awk引用外部变量

控制结构,和C相同,if [else if] else, for(;;),while(){}, do{}while(),break,continue

next致使读入下一个输入行,并返回到脚本底部,能够避免当前输入行执行其余操做  。 exit是输入主循环退出,转到END规则。没有END或者在END中用exit则终止脚本的执行。exit可使用一个表达式做为参数,做为awk的退出状态返回。

数组

a[sub]=value,没必要指明数组大小,awk的全部数组都是关联数组,下标可使字符串和数字。

遍历:for( var in arr )do something with arr[var] ,访问顺序随机。 eg: arr[grade]++ ,即便grade最初不在数组arr中。

重要的是记住awk中的全部下标都是字符串型的,即便使用数字做为下标,awk自动将它们转为字符串,当使用浮点数作下标时向字符串转可能会有影响。

成员测试: item in array, 存在返回1,不然返回0。   awk应用小结(全部命令行均经调试) 

split()建立数组: n=split(str, array, sep), 返回元素个数,sep能够是正则。

删除数组元素: delete array[sub]

模拟多维数组: array[3,2], 成员测试时下标必须放置在圆括号中。 if((i,j) in array)。 多维数组的下标分别解释为单独的字符串,用系统变量SUBSEP链接,默认为“\034”。

多维数组循环: for(item in array) split(item,sub,SUBSEP). 必须用split()函数来访问单独的下标份量,split使用下标item建立数组sub。

系统变量的数组: 命令行参数ARGV,下标0到ARGC-1,不包括脚本名和选项,ARGV[0]是'awk'。  ENVIRON环境变量数组,其中下标是环境变量的名字。

 能够向ARGV数组添加元素,可是注意要同时增长ARGC的值,awk使用ARGC的值来获得ARGV中有多少元素能够处理。若是ARGV的元素值是一个空串awk将跳过它。

函数

数学函数...

取整int(),print int(100/3)

rand()生成0到1之间的浮点随机数。srand()为随机数发生器设置一个种子数或者起点数,srand([x]),不带参数是使用当前时间。

字符串函数:字符串的起始位置为1,

sub(regex,s,[t=$0]),替换第一个出现的,成功返回1不然返回0. gsub(regex,s,[t=$0])返回替换的个数。正则用//包围。 直接改变指定字符窜,返回的不是替换后的字符串。 和sed同样,替换字符串中的&将被正则匹配的字符串代替。\&表明"&",在字符串中必须输入两个\\。

index(s,t)返回t在s中的位置,没有指定s返回0. length([s=$0])。

match(s,regex),正则用//包围,返回regex出现的起始位置,若没有,返回0。设置RSTART和RLENGTH的值。能够用在while循环中,但在每次循环中要改变已匹配的[RSTART..RSTART+RLENGTH]部分,使下次循环是再也不匹配已匹配的部分。   注意sub的正则在前面,match的正则在后面。

split(s,arr,sep)返回元素个数,没有sep则用FS。

sprintf(fmt,ecpr),  substr(s,p,[n]),子串p开始最大长度为n。 tolower(s), toupper(s)。

lowerChars="abcdef..."; f=substr($1,1,1); if(i=index(lowerChars,f)) $1=substr(upperChars,i,1) substr($1,2) #首字母改大写

awk 用法 Awk 命令学习总结 Linux Shell经常使用技巧(五) awk编程 awk使用手册

自定义函数

function name(arg1,arg2,..){ statements }  return 语句返回。

函数参数都是局部变量。 函数体重定义的变量默认为全局变量。 能够将局部的临时变量列在参数列表末尾。 在参数列表中参数按顺序接受传递来的值。其余的参数初始化为空串。

高级主题

getline函数用于从输入中读取另外一行。也能处理来自文件和管道的输入。next语句也是读取下一行,可是next语句将控制传递到脚本的顶部。getline函数获得下一行但不改变脚本的控制。返回值,1:读取一行, 0:到达文件末尾, -1:遇到错误。 尽管被称为一个函数,可是它相似于一个语句,且不能写成getline()。   while(getline > 0) cmd=amd $0

当读取新行后,getline将它赋给$0,并将它分解成字段,同时设置NF,NR,FNR。所以新行变成当前行。若是须要,能够用getline读取一行并将它赋给一个变量从而避免改变$0。 getline var

从文件中读取:while( (getline < "data") > 0 ) ,"data"是一个文件名字符串。加括号是为了防止混乱。

标准输入读取: getline [var] < "-"

将输入赋值给变量:getline var 不是var = getline, 对$0没有影响。输入行没有被分解为字段,对NF没有影响。但它递增了记录计数器NR, FNR。

从管道读取: "who an i" | getline .将命令的结果赋给$0,同时设置系统变量。$0被改变,$1,NF等变量确定都跟着改变,它也是根据FS来分隔字段,因此要注意改变FS的地方。 即便$0不改变,NR, FNR也会改变。

当包含多个输入行时getline一次读取一行, 要读取全部行就必须建立一个循环来执行getline直到再也不有输出为止。while("who" | getline)...注意:其中who命令值执行一次,可是getline则调用屡次。

 close()函数: 关闭打开的文件或管道。

由于:1. 每次只能代开必定数量的管道。 一般用在getline返回0或-1是,如close("who"). 2. 关闭管道使得你能够运行用一个命令两次。 3.为了获得一个输出管道来完成它的工做,使用close()多是必要的,{some processing of $0 | "sort > tmpfile"}  END{close("sort > tmpfile")}

system()函数执行命令。然而它没有产生可供程序处理的输出。它返回被执行命令的退出状态。 if(system("mkdir dale") != 0) print "failed!"

 直接向文件或管道输出:

print和printf能够用输出重定向操做">"和">>"将结果直接写入到文件中。  print > data.out 将记录写入data.out

print | command 直接暑促到管道。该命令在第一次执行时打开一个管道,并将当前记录做为输入传送给命令,换句话说这里的命令只执行一次,但每执行一次print将提供另外一个输入行。

相关文章
相关标签/搜索