Awk日常使用技巧合辑 ======================================== Linux awk内置变量 $0 当前记录(即当前的一整行作为“单个变量”) $1-$n 当前记录的第n个字段,字段间由FS分隔 NF 当前记录中的字段个数(就是有多少列),所以$NF指的就是当前行中的最后一个字段 NR 已经读出的记录数(就是行号,从1开始),一般就是指输入的“行数“ FNR 当前记录数(它与NR的区别我还没有弄明白?) RS 输入记录的分隔符(默认为换行符) ORS 输出记录的分隔符(默认为换行符) FS 输入字段分隔符(默认为空格) OFS 输出字段分隔符(默认为空格) FILENAME 当前输入文件的名字 ARGC 命令行参数个数 ARGV 命令行参数数组 ENVIRON UNIX环境变量 实例如下: 1、常用操作 [chengmo@localhost ~]$ awk '/^root/{print $0}' /etc/passwd root:x:0:0:root:/root:/bin/bash /^root/ 为选择表达式,$0代表是逐行 2、设置字段分隔符号(FS使用方法) [chengmo@localhost ~]$ awk 'BEGIN{FS=":"}/^root/{print $1,$NF}' /etc/passwd root /bin/bash FS为字段分隔符,可以自己设置,默认是空格,因为passwd里面是”:”分隔,所以需要修改默认分隔符。NF是字段总数,$0代表当前行记录,$1-$n是当前行,各个字段对应值。 3、记录条数(NR,FNR使用方法) [chengmo@localhost ~]$ awk 'BEGIN{FS=":"}{print NR,$1,$NF}' /etc/passwd 1 root /bin/bash 2 bin /sbin/nologin 3 daemon /sbin/nologin 4 adm /sbin/nologin 5 lp /sbin/nologin 6 sync /bin/sync 7 shutdown /sbin/shutdown …… NR得到当前记录所在行 4、设置输出字段分隔符(OFS使用方法) [chengmo@localhost ~]$ awk 'BEGIN{FS=":";OFS="^^"}/^root/{print FNR,$1,$NF}' /etc/passwd 1^^root^^/bin/bash OFS设置默认字段分隔符 5、设置输出行记录分隔符(ORS使用方法) [chengmo@localhost ~]$ awk 'BEGIN{FS=":";ORS="^^"}{print FNR,$1,$NF}' /etc/passwd 1 root /bin/bash^^2 bin /sbin/nologin^^3 daemon /sbin/nologin^^4 adm /sbin/nologin^^5 lp /sbin/nologin 从上面看,ORS默认是换行符,这里修改为:”^^”,所有行之间用”^^”分隔了。 关于awk中ARGC/ARGV的一些知识点还不是很明白: 输入参数获取(ARGC ,ARGV使用) [chengmo@localhost ~]$ awk 'BEGIN{FS=":";print "ARGC="ARGC;for(k in ARGV) {print k"="ARGV[k]; }}' /etc/passwd ARGC=2 0=awk 1=/etc/passwd ARGC得到所有输入参数个数,ARGV获得输入参数内容,是一个数组。(awk自身的一些设置不包括?) ======================================== 超牛逼/实用的awk技巧 一些注意事项: 其中单引号中的被大括号括着的就是awk的语句,注意,其只能被单引号包含。 其中的$1..$n表示第几列。注:$0表示整个行。 在进行一些稍微复杂点的awk使用时,经常会碰到END关键字。END的意思是“处理完所有的行的标识”,即然说到了END就有必要介绍一下BEGIN,这两个关键字意味着执行前和执行后的意思,语法如下: BEGIN{ 这里面放的是执行前的语句 } END {这里面放的是处理完所有的行后要执行的语句 } {这里面放的是处理每一行时要执行的语句} 用awk来过滤记录: $ awk '$3==0 && $6=="LISTEN" ' netstat.txt 其中的“==”为比较运算符。其他比较运算符:!=, >, <, >=, <= $ awk ' $3>0 {print $0}' netstat.txt Proto Recv-Q Send-Q Local-Address Foreign-Address State tcp 0 4166 coolshell.cn:80 61.148.242.38:30901 ESTABLISHED tcp 0 1 coolshell.cn:80 124.152.181.209:26825 FIN_WAIT1 tcp 0 1 coolshell.cn:80 208.115.113.92:50601 LAST_ACK 如果我们需要表头的话,我们可以引入内建变量NR: $ awk '$3==0 && $6=="LISTEN" || NR==1 ' netstat.txt Proto Recv-Q Send-Q Local-Address Foreign-Address State tcp 0 0 0.0.0.0:3306 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN awk的内建变量: $0 当前记录(这个变量中存放着整个行的内容) $1~$n 当前记录的第n个字段,字段间由FS分隔 FS 输入字段分隔符 默认是空格或Tab NF 当前记录中的字段个数,就是有多少列 NR 已经读出的记录数,就是行号,从1开始,如果有多个文件话,这个值也是不断累加中。 FNR 当前记录数,与NR不同的是,这个值会是各个文件自己的行号 RS 输入的记录分隔符, 默认为换行符 OFS 输出字段分隔符, 默认也是空格 ORS 输出的记录分隔符,默认为换行符 FILENAME 当前输入文件的名字 折分文件 awk拆分文件很简单,使用重定向就好了。下面这个例子,是按第6例分隔文件,相当的简单(其中的NR!=1表示不处理表头)。 $ awk 'NR!=1{print > $6}' netstat.txt 统计 下面的命令计算所有的C文件,CPP文件和H文件的文件大小总和。 $ ls -l *.cpp *.c *.h | awk '{sum+=$5} END {print sum}' 2511401 http://coolshell.cn/articles/9070.html ======================================== awk实现求和、平均、最大值和最小值的计算操作 0、准备和数据文件 比如有一个数据文件,只有一列(在之前可以通过各种手段过滤出只有数字这一列) 490898 1189235 20212 1494270 146515 29369 23563 563027 22976 127809 16813 551646 18858 18977 1、求和 cat data | awk '{sum+=$1} END {print "Sum = ", sum}' 2、求平均 cat data | awk '{sum+=$1} END {print "Average = ", sum/NR}' 3、求最大值 cat data|awk 'BEGIN{max=0} {if ($1+0 > max+0) max=$1 fi} END{print "Max=", max}' 4、求最小值(min的初始值设置一个超大数即可) awk 'BEGIN{min = 1999999} {if ($1+0 < min+0) min=$1 fi} END{print "Min=", min}' 5、求访问次数的Top 10 Resource,可以根据此进行优化 cat output/logs/cookie_logs/`date +%u`/cookie_log | grep -v '172.16' | grep -v '127.0.0.1' | awk -F' ' '{ if(index($1,"219.141.246")!=0) print $2; else print $1 }' | sort | uniq -c | sort -n | tail -10 ======================================== 打印文件的第一列(域): awk '{print $1}' filename 打印文件的前两列(域): awk '{print $1,$2}' filename 打印文本文件的总行数: awk 'END{print NR}' filename #END必不可少 如果想要把某一文件的总行数赋值给变量nlines,可以表达为: 1) nlines=`(awk 'END{print NR}' filename)` 或者 2) nlines=$(awk 'END{print NR}' filename) 让awk打印除第一列外的所有列怎么写? 方法一: awk '{for(iCnt=2;iCnt<=NF;iCnt++)print $iCnt}' urfile 方法二: awk '{$1="";print $0}' filename awk合并文件问题 我有2个文件 tmp1.txt 和 tmp2.txt tmp1.txt 20 18 19 tmp2.txt 15 14 13 我想做个文件tmp3.txt做成 20 15 18 14 19 13 就是把tmp1和tmp2按列合并。 方法一: 使用paste命令:paste tmp1.txt tmp2.txt >tmp3.txt 方法二: awk 'NR==FNR{a[NR]=$1;count=NR}NR>FNR{b[NR-count]=$1}END{for(i=1;i<=count;i++)print a[i],b[i]}' tmp1.txt tmp2.txt | tee tmp3.txt 方法三: awk 'NR==FNR{a[NR]=$0}NR>FNR{print a[FNR],$0}' tmp1.txt tmp2.txt | tee tmp3.txt ======================================== awk 正则表达式、正则运算符详细介绍 http://www.cnblogs.com/chengmo/archive/2010/10/11/1847772.html http://www.cnblogs.com/chengmo/archive/2010/10/10/1847287.html http://www.cnblogs.com/chengmo/archive/2010/10/08/1845913.html 前言:使用awk作为文本处理工具,正则表达式是少不了的。 要掌握这个工具的正则表达式使用。其实,我们不必单独去学习它的正则表达式。正则表达式就像一门程序语言,有自己语法规则已经表示意思。 对于不同工具,其实大部分表示意思相同的。在linux众多文本处理工具(awk,sed,grep,perl)里面用到正则表达式。其实就只有3种类型。详细可以参考:linux shell 正则表达式(BREs,EREs,PREs)差异比较 。只要是某些工具是属于某种类型的正则表达式。那么它的语法规则基本一样。 通过那篇文章,我们知道awk的正则表达式,是属于:扩展的正则表达式(Extended Regular Expression 又叫 Extended RegEx 简称 EREs)。 一、awk Extended Regular Expression (ERES)基础表达式符号介绍 字符 功能 + 指定如果一个或多个字符或扩展正则表达式的具体值(在 +(加号)前)在这个字符串中,则字符串匹配。命令行: awk '/smith+ern/' testfile 将包含字符 smit,后跟一个或多个 h 字符,并以字符 ern 结束的字符串的任何记录打印至标准输出。此示例中的输出是: smithern, harry smithhern, anne ? 指定如果零个或一个字符或扩展正则表达式的具体值(在 ?(问号)之前)在字符串中,则字符串匹配。命令行: awk '/smith?/' testfile 将包含字符 smit,后跟零个或一个 h 字符的实例的所有记录打印至标准输出。此示例中的输出是: smith, alan smithern, harry smithhern, anne smitters, alexis | 指定如果以 |(垂直线)隔开的字符串的任何一个在字符串中,则字符串匹配。命令行: awk '/allen | alan /' testfile 将包含字符串 allen 或 alan 的所有记录打印至标准输出。此示例中的输出是: smiley, allen smith, alan ( ) 在正则表达式中将字符串组合在一起。命令行: awk '/a(ll)?(nn)?e/' testfile 将具有字符串 ae 或 alle 或 anne 或 allnne 的所有记录打印至标准输出。此示例中的输出是: smiley, allen smithhern, anne {m} 指定如果正好有 m 个模式的具体值位于字符串中,则字符串匹配。命令行: awk '/l{2}/' testfile 打印至标准输出 smiley, allen {m,} 指定如果至少 m 个模式的具体值在字符串中,则字符串匹配。命令行: awk '/t{2,}/' testfile 打印至标准输出: smitters, alexis {m, n} 指定如果 m 和 n 之间(包含的 m 和 n)个模式的具体值在字符串中(其中m <= n),则字符串匹配。命令行: awk '/er{1, 2}/' testfile 打印至标准输出: smithern, harry smithern, anne smitters, alexis [String] 指定正则表达式与方括号内 String 变量指定的任何字符匹配。命令行: awk '/sm[a-h]/' testfile 将具有 sm 后跟以字母顺序从 a 到 h 排列的任何字符的所有记录打印至标准输出。此示例的输出是: smawley, andy [^ String] 在 [ ](方括号)和在指定字符串开头的 ^ (插入记号) 指明正则表达式与方括号内的任何字符不匹配。这样,命令行: awk '/sm[^a-h]/' testfile 打印至标准输出: smiley, allen smith, alan smithern, harry smithhern, anne smitters, alexis ~,!~ 表示指定变量与正则表达式匹配(代字号)或不匹配(代字号、感叹号)的条件语句。命令行: awk '$1 ~ /n/' testfile 将第一个字段包含字符 n 的所有记录打印至标准输出。此示例中的输出是: smithern, harry smithhern, anne ^ 指定字段或记录的开头。命令行: awk '$2 ~ /^h/' testfile 将把字符 h 作为第二个字段的第一个字符的所有记录打印至标准输出。此示例中的输出是: smithern, harry $ 指定字段或记录的末尾。命令行: awk '$2 ~ /y$/' testfile 将把字符 y 作为第二个字段的最后一个字符的所有记录打印至标准输出。此示例中的输出是: smawley, andy smithern, harry . (句号) 表示除了在空白末尾的终端换行字符以外的任何一个字符。命令行: awk '/a..e/' testfile 将具有以两个字符隔开的字符 a 和 e 的所有记录打印至标准输出。此示例中的输出是: smawley, andy smiley, allen smithhern, anne *(星号) 表示零个或更多的任意字符。命令行: awk '/a.*e/' testfile 将具有以零个或更多字符隔开的字符 a 和 e 的所有记录打印至标准输出。此示例中的输出是: smawley, andy smiley, allen smithhern, anne smitters, alexis \ (反斜杠) 转义字符。当位于在扩展正则表达式中具有特殊含义的任何字符之前时,转义字符除去该字符的任何特殊含义。例如,命令行: /a\/\// 将与模式 a // 匹配,因为反斜杠否定斜杠作为正则表达式定界符的通常含义。要将反斜杠本身指定为字符,则使用双反斜杠。有关反斜杠及其使用的更多信息,请参阅以下关于转义序列的内容。 与PERs相比,主要是一些结合类型表示符没有了:包括:”\d,\D,\s,\S,\t,\v,\n,\f,\r”其它功能基本一样的。 我们常见的软件:javascript,.net,java支持的正则表达式,基本上是:EPRs类型。 二、awk 常见调用正则表达式方法 awk语句中: awk ‘/REG/{action}’ /REG/为正则表达式,可以将$0中,满足条件记录 送入到:action进行处理. awk正则运算语句(~,~!等同!~) [chengmo@centos5 ~]$ awk 'BEGIN{info="this is a test";if( info ~ /test/){print "ok"}}' ok awk内置使用正则表达式函数 gsub( Ere, Repl, [ In ] ) sub( Ere, Repl, [ In ] ) match( String, Ere ) split( String, A, [Ere] ) 详细函数使用,可以参照:linux awk 内置函数详细介绍(实例) ======================================== http://www.pement.org/awk/awk1line.txt ============================================================================ Sed日常使用技巧合辑 ======================================== sed的几个常用用法 Linux下sed是个流文本编辑器,它一次处理一行内容,处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直到文件末尾。文件内容并没有改变,除非你使用重定向存储输出或使用sed -i参数进行保存。Sed主要用来自动编辑一个或多个文件;简化对文件的反复操作;编写转换程序等。 1. 去掉空行 sed ‘/^$/d’ yourfile 2. 在shell中,用某个变量(参数)替换文本中的指定字符串,如果在sed中引用变量,必须用双引号“哦。否则变量不生效 如用$myarg变量替换myfreelinux.com myarg="test arg" echo “linux site:http://www.myfreelinux.com” | sed “s/myfreelinux.com/$myarg/g” 结果: linux site:http://www.test arg 3. 删除(去掉)每行末尾的最后一个字符,行末尾的任意一个字符都会被删除哦,常用场景构造mysql多行insert值的sql语句 sed ‘s/.$//’ yourfile 4.替换字符(含有/特殊符号的),这里命令中的斜杠/可以用其他符号代替,如用#号 如把/用@替换 echo “http://myfreelinux.com/” | sed ‘s#/#@#g’ 如果一定要用/斜杠的话,命令必须把要替换的斜杠先转义 echo “http://myfreelinux.com/” | sed ‘s/\//@/g’ 5. 在行首或者行尾增加字符串 如在行首增加myfreelinux.com echo “mychar” | sed ‘s/^/myfreelinux.com/g’ 在行尾增加myfreelinux.com echo “mychar” | sed ‘s/$/myfreelinux.com/g’ 6.删除第N行: sed ‘Nd’ filename 删除第M到N行: sed ‘M,Nd’ filename 7.删除匹配内容所在的行 sed /PATTERN/d filename 8.匹配内容后增加某内容 在匹配forbag.cn内容后增加myfreelinux.com这一行内容 sed ‘/forbag.cn/a\myfreelinux.com’ youfile 在匹配forbag.cn内容前增加myfreelinux.com这一行内容 sed ‘/forbag.cn/i\myfreelinux.com’ youfile 9.匹配字符串,然后在匹配的行之下插入多行文本(即插入一个文件),该文本预先写入某个文件 在yourfile匹配myfreelinux.com内容后增加forbag.txt这个文件 sed -i ‘/myfreelinux.com r forbag.txt’ yourfile ======================================== sed '/script/d' | sed '/ac_/d' # 删除文件中的最后一行 sed '$d' # 复制文档中两个正则表达式之间的内容(相当有用啊!相见恨晚) sed '/Iowa/,/Montana/p' # 在每一行开头处插入5个空格(使全文向右移动5个字符的位置) sed 's/^/ /' # 对文件中的所有行编号(行号在左,文字右端对齐)。 sed = filename | sed 'N; s/^/ /; s/ *\(.\{6,\}\)\n/\1 /' # 对文件中的所有行编号,但只显示非空白行的行号。 sed '/./=' filename | sed '/./N; s/\n/ /' 选择性地删除特定行: -------- # 显示通篇文档,除了两个正则表达式之间的内容 sed '/Iowa/,/Montana/d' # 删除文件中相邻的重复行(模拟“uniq”) # 只保留重复行中的第一行,其他行删除 sed '$!N; /^\(.*\)\n\1$/!P; D' # 删除文件中的重复行,不管有无相邻。注意hold space所能支持的缓存 # 大小,或者使用GNU sed。 sed -n 'G; s/\n/&&/; /^\([ -~]*\n\).*\n\1/d; s/\n//; h; P' # 删除除重复行外的所有行(模拟“uniq -d”) sed '$!N; s/^\(.*\)\n\1$/\1/; t; D' # 删除文件中开头的10行 sed '1,10d' # 删除文件中的最后一行 sed '$d' # 删除文件中的最后两行 sed 'N;$!P;$!D;$d' # 删除文件中的最后10行 sed -e :a -e '$d;N;2,10ba' -e 'P;D' # 方法1 sed -n -e :a -e '1,10!{P;N;D;};N;ba' # 方法2 # 删除8的倍数行 gsed '0~8d' # 只对GNU sed有效 sed 'n;n;n;n;n;n;n;d;' # 其他sed # 删除匹配式样的行 sed '/pattern/d' # 删除含pattern的行。当然pattern # 可以换成任何有效的正则表达式 # 删除文件中的所有空行(与“grep '.' ”效果相同) sed '/^$/d' # 方法1 sed '/./!d' # 方法2 # 只保留多个相邻空行的第一行。并且删除文件顶部和尾部的空行。 # (模拟“cat -s”) sed '/./,/^$/!d' #方法1,删除文件顶部的空行,允许尾部保留一空行 sed '/^$/N;/\n$/D' #方法2,允许顶部保留一空行,尾部不留空行 # 只保留多个相邻空行的前两行。 sed '/^$/N;/\n$/N;//D' # 删除文件顶部的所有空行 sed '/./,$!d' # 删除文件尾部的所有空行 sed -e :a -e '/^\n*$/{$d;N;ba' -e '}' # 对所有sed有效 sed -e :a -e '/^\n*$/N;/\n$/ba' # 同上,但只对 gsed 3.02.*有效 # 删除每个段落的最后一行 sed -n '/^$/{p;h;};/./{x;/./p;}' sed = vpn_log.txt | sed 'N;s/\n/\t/' sed '/./=' vpn_log.txt | sed '/./N; s/\n/ /' sed = vpn_log.txt | sed 'N; s/^/ /; s/ *\(.\{6,\}\)\n/\1 /' ======================================== sed基本命令笔记 替换字符(含有/特殊符号的),这里命令中的斜杠/可以用其他符号代替,如用#号 如把/用@替换 echo “http://myfreelinux.com/” | sed ‘s#/#@#g’ 如果一定要用/斜杠的话,命令必须把要替换的斜杠先转义 echo “http://myfreelinux.com/” | sed ‘s/\//@/g’ 匹配内容后增加某内容 在匹配forbag.cn内容后增加myfreelinux.com这一行内容 sed ‘/forbag.cn/a\myfreelinux.com’ youfile 在匹配forbag.cn内容前增加myfreelinux.com这一行内容 sed ‘/forbag.cn/i\myfreelinux.com’ youfile $ sed 's#10#100#g' example-----不论什么字符,紧跟着s命令的都被认为是新的分隔符,所以,“#”在这里是分隔符,代替了默认的“/”分隔符。表示把所有10替换成100。 选定行的范围:逗号 $ sed -n '/test/,/check/p' example-----所有在模板test和check所确定的范围内的行都被打印 $ sed -n '5,/^test/p' example-----打印从第五行开始到第一个包含以test开始的行之间的所有行 $ sed '/test/,/check/s/$/sed test/' example-----对于模板test和check之间的行,每行的末尾用字符串sed test替换 从文件读入:r命令 $ sed '/test/r file' example-----file里的内容被读进来,显示在与test匹配的行后面,如果匹配多行,则file的内容将显示在所有匹配行的下面 [root@Jason64-17 sed]# cat sed-4.txt 1 2 3 4 5 6 7 8 9 10 [root@Jason64-17 sed]# cat sed-1.txt i am lisp i have a computer it is very big and i have no room google is very nice my friends usual alias nice for me [root@Jason64-17 sed]# sed '/very/r sed-4.txt' sed-1.txt i am lisp i have a computer it is very big 1 2 3 4 5 6 7 8 9 10 and i have no room google is very nice 1 2 3 4 5 6 7 8 9 10 my friends usual alias nice for me [root@Jason64-17 sed]# sed -n '/very/r sed-4.txt' sed-1.txt 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10