免费注册 查看新帖 |

ChinaUnix.net

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 96442 | 回复: 121

[学习共享] 文本编辑的一点心得--awk篇 [复制链接]

论坛徽章:
23
15-16赛季CBA联赛之吉林
日期:2017-12-21 16:39:27白羊座
日期:2014-10-27 11:14:37申猴
日期:2014-10-23 08:36:23金牛座
日期:2014-09-30 08:26:49午马
日期:2014-09-29 09:40:16射手座
日期:2014-11-25 08:56:112015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:49:0315-16赛季CBA联赛之山东
日期:2017-12-21 16:39:1915-16赛季CBA联赛之广东
日期:2016-01-19 13:33:372015亚冠之山东鲁能
日期:2015-10-13 09:39:062015亚冠之西悉尼流浪者
日期:2015-09-21 08:27:57
发表于 2010-09-23 13:24 |显示全部楼层
本帖最后由 ly5066113 于 2014-04-30 08:35 编辑

本文模仿十三问,以提问和回答的方式介绍awk的一些基础知识。论坛里awk高手众多,有错误的地方还请大家指正。


本文所有用例的测试环境采用unix-center的ubuntu服务器
http://www.unix-center.net/

具体版本如下:
  1. ly5066113@ubuntu:~$ uname -a
  2. Linux ubuntu 2.6.24-22-generic #1 SMP Mon Nov 24 19:35:06 UTC 2008 x86_64 GNU/Linux
  3. ly5066113@ubuntu:~$ bash --version
  4. GNU bash, version 3.2.39(1)-release (x86_64-pc-linux-gnu)
  5. Copyright (C) 2007 Free Software Foundation, Inc.
  6. ly5066113@ubuntu:~$ awk --version
  7. GNU Awk 3.1.6
  8. Copyright (C) 1989, 1991-2007 Free Software Foundation.
复制代码
一、RS 与 ORS 差在哪

我们经常会说,awk是基于行列操作文本的,但如何定义“行”呢?这就是RS的作用。
默认情况下,RS的值是\n。下面通过实例来理解下RS。
  1. ly5066113@ubuntu:~$ echo '1a2a3a4a5' | awk '{print $1}'
  2. 1a2a3a4a5
  3. ly5066113@ubuntu:~$ echo '1a2a3a4a5' | awk 'BEGIN{RS="a"}{print $1}'
  4. 1
  5. 2
  6. 3
  7. 4
  8. 5
复制代码
我们可以看到,在更改了RS的值后,awk定义的行已经不是我们实际意义中的行了。
上面RS固定的字符串,RS也可以定义为正则表达式。
  1. ly5066113@ubuntu:~$ echo '1ab2bc3cd4de5' | awk 'BEGIN{RS="[a-z]+"}{print $1,RS,RT}'
  2. 1 [a-z]+ ab
  3. 2 [a-z]+ bc
  4. 3 [a-z]+ cd
  5. 4 [a-z]+ de
  6. 5 [a-z]+
复制代码
当我们将RS设置为正则表达式的时候,RT这个变量就有作用了,RS的值始终为我们设定的正则,RT的值则是这个正则实际匹配到的内容。
下面我们看看将RS设置为空会是什么情况
  1. ly5066113@ubuntu:~$ cat urfile
  2. 1

  3. 2


  4. 3








  5. 4
  6. ly5066113@ubuntu:~$ awk 'BEGIN{RS=""}{print $0}' urfile
  7. 1
  8. 2
  9. 3
  10. 4
复制代码
如果RS被设置为空,那么awk会将连续的空行作为行分隔符,与RS设置成"\n\n+"有什么区别???
1、忽略文件开头和结尾的空行。且文件不以记录分隔符结束,即最后不是空行,会将最后一个记录的尾\n去掉
2、设置RT变量未空
3、影响FS变量
这个怎么理解?对于1、2两点,当作习题留给大家自己测试,3我们下节来讲。

总结下RS的3种情况:
1) 非空字符串
   以固定字符串作为行分隔符,同时设置变量RT为固定字符串
2) 正则表达式
   以正则表达式作为行分隔符,同时设置变量RT为正则表达式实际匹配到的字符串
3) 空字符
   以连续的空行作为行分隔符,如果FS为单个字符,会将\n强制加入到FS变量中

理解了RS,再来理解ORS就简单了。RS是awk读取文件时的行分隔符,ORS则是awk输出时的行结束符。
更简单的讲,就是awk在输出时,会在每行记录后面增加一个ORS变量所设定的值。
ORS的值只能设定为字符串,默认情况下,ORS的值是\n
  1. ly5066113@ubuntu:~$ seq 5 | awk '{print $0}'
  2. 1
  3. 2
  4. 3
  5. 4
  6. 5
  7. ly5066113@ubuntu:~$ seq 5 | awk 'BEGIN{ORS="a"}{print $0}'
  8. 1a2a3a4a5a
复制代码
我们平常用的 print $0 等价于 printf $0 ORS


二、FS 与 OFS 差在哪

RS是awk用来定义“行”的,那么FS就是awk用来定义“列”的。
设置变量 FS 与使用 -F 参数是一样的。
  1. ly5066113@ubuntu:~$ echo '1,2' | awk -F , '{print $1}'
  2. 1
  3. ly5066113@ubuntu:~$ echo '1,2' | awk 'BEGIN{FS=","}{print $1}'
  4. 1
复制代码
与 RS 类似,FS 同样可以设置为正则表达式
  1. ly5066113@ubuntu:~$ echo '1ab2bc3cd4de5' | awk 'BEGIN{FS="[a-z]+"}{print $1,$2,$5}'
  2. 1 2 5
复制代码
FS 有1个特例,就是将FS设置为一个空格,FS=" " ,这也是FS的默认值
  1. In the special case that FS is a single space, fields are separated by runs of spaces and/or tabs and/or newlines.
复制代码
此时,awk会将连续的 空格 或 制表符(\t) 或 换行符(\n) 作为列的分隔符
那么,FS=" " 与 FS="[ \t\n]+" 有区别么???
答案是肯定的
  1. ly5066113@ubuntu:~$ echo ' 1 2' | awk 'BEGIN{FS=" "}{print $1}'
  2. 1
  3. ly5066113@ubuntu:~$ echo ' 1 2' | awk 'BEGIN{FS="[ \t\n]+"}{print $1}'

复制代码
当FS=" "时,awk会自动去掉行首和行尾的 空格 或 制表符(\t) 或 换行符(\n),但FS="[ \t\n]+"是不会的
同样,FS也可以设置为空
  1. ly5066113@ubuntu:~$ echo '123' | awk 'BEGIN{FS=""}{print $1,$2}'
  2. 1 2
复制代码
当FS被设置为空字符串的时候,awk会将一行记录的每个字符做为单独的一列
类似的,当我们想以固定的长度来分隔列的时候,可以使用 FIELDWIDTHS 来代替 FS
例如,一行记录的前3个字符作为第一列,接下来的2个字符作为第二列,接下来的4个字符作为第三列
  1. ly5066113@ubuntu:~$ echo '123456789' | awk 'BEGIN{FIELDWIDTHS="3 2 4"}{print $1,$2,$3}'
  2. 123 45 6789
  3. ly5066113@ubuntu:~$ echo '123456789' | awk 'BEGIN{FIELDWIDTHS="3 2 3"}{print $1,$2,$3}'
  4. 123 45 678
  5. ly5066113@ubuntu:~$ echo '123456789' | awk 'BEGIN{FIELDWIDTHS="3 2 5"}{print $1,$2,$3}'
  6. 123 45 6789
复制代码
如果定义的长度小于实际的长度,awk会截断,如果大于实际长度,则以实际长度为准。

总结下FS的4种情况:
1) 非空字符串
   以固定字符串作为列分隔符
2) 正则表达式
   以正则表达式作为列分隔符
3) 单个空格
   以连续的 空格 或 制表符(\t) 或 换行符(\n)作为列分隔符
4) 空字符
   以每个字符做为单独的一列

接下来我们来看看上节提到的问题:
当 RS="" 时,会将\n强制加入到FS变量中
  1. ly5066113@ubuntu:~$ cat urfile
  2. 1
  3. a

  4. 2
  5. a


  6. 3
  7. ly5066113@ubuntu:~$ awk -v RS="" '{print "#" $0 "#"}' urfile
  8. #1
  9. a#
  10. #2
  11. a#
  12. #3#
  13. ly5066113@ubuntu:~$ awk -F "b" -v RS="" '{print $1}' urfile
  14. 1
  15. 2
  16. 3
  17. ly5066113@ubuntu:~$ awk -F "c" -v RS="" '{print $1}' urfile
  18. 1
  19. 2
  20. 3
  21. ly5066113@ubuntu:~$ awk -F "c" -v RS="\n\n+" '{print "#" $1 "#"}' urfile
  22. #1
  23. a#
  24. #2
  25. a#
  26. #3
  27. #
复制代码
如果FS为单个字符,\n始终存在在 FS 中,而 RS="\n\n+" 则不会。

了解的 FS ,我们来看看 OFS ,FS是awk读入记录时的列分隔符,OFS则是awk输出时的列分隔符。
我们平时使用的 print $1,$2 等价于 print $1 OFS $2
  1. ly5066113@ubuntu:~$ echo '1 2' | awk -v OFS="|" '{print $1,$2}'
  2. 1|2
  3. ly5066113@ubuntu:~$ echo '1 2' | awk -v OFS="|" '{print $1 OFS $2}'
  4. 1|2
复制代码
如果一行记录有很多列,同时想改变输出的分隔符,print $1,$2,$3 ... 岂不是很麻烦?
当然有简单的方法:
  1. ly5066113@ubuntu:~$ echo '1 2 3 4 5' | awk -v OFS="|" '{print $0}'
  2. 1 2 3 4 5
  3. ly5066113@ubuntu:~$ echo '1 2 3 4 5' | awk -v OFS="|" '{$1=$1;print $0}'
  4. 1|2|3|4|5
  5. ly5066113@ubuntu:~$ echo '1 2 3 4 5' | awk -v OFS="|" '{NF+=0;print $0}'
  6. 1|2|3|4|5
复制代码
为了使OFS的设置生效,需要改变 $0 ,这里我们是对 awk 撒了个小谎
$1=$1 或者 NF+=0, $0 本身的内容实际上没有任何改变,只是为了使 OFS 的设置生效

在理解了 RS 和 FS 之后,我们来回顾开始的那句话:“awk是基于行列操作文本的”
这个说法实际上不是很准确,因为在改变了 RS 后,awk 中的“行”已经不是一般的“行”了
同样,改变了 FS 后,awk 中的“列”也已经不是一般的“列”了
因此,准确的应该这样讲:“awk是基于 记录(record) 和 域(field) 操作文本的”


三、0 与 "0" 差在哪

我们先来看一个例子:
  1. ly5066113@ubuntu:~$ awk 'BEGIN{if(0) print "true";else print "false"}'
  2. false
  3. ly5066113@ubuntu:~$ awk 'BEGIN{if("0") print "true";else print "false"}'
  4. true
复制代码
为什么同样是 0 ,结果却不一样?
其实要解释这个问题,只需要弄清楚awk中的“真”与“假”。
以下3种情况是“假”,其他情况都为“真”
1) 数字 0
2) 空字符串
3) 未定义的值
  1. ly5066113@ubuntu:~$ awk 'BEGIN{a=0;if(a) print "true";else print "false"}'
  2. false
  3. ly5066113@ubuntu:~$ awk 'BEGIN{a="";if(a) print "true";else print "false"}'
  4. false
  5. ly5066113@ubuntu:~$ awk 'BEGIN{if(a) print "true";else print "false"}'
  6. false
复制代码
以上是普通的字符测试,对于是表达式的情况,先计算表达式,然后将结果按上面的情况测试
  1. ly5066113@ubuntu:~$ awk 'BEGIN{if(a=1) print "true";else print "false"}'
  2. true
  3. ly5066113@ubuntu:~$ awk 'BEGIN{if(a=0) print "true";else print "false"}'
  4. false
  5. ly5066113@ubuntu:~$ awk 'BEGIN{if(a="0") print "true";else print "false"}'
  6. true
  7. ly5066113@ubuntu:~$ awk 'BEGIN{if(a="") print "true";else print "false"}'
  8. false
  9. ly5066113@ubuntu:~$ awk 'BEGIN{if(a=a) print "true";else print "false"}'
  10. false
复制代码
来看一个被大家称为月经的问题,awk如何去重?
  1. awk '! a[$0] ++'
复制代码
在解释之前,我们先要了解awk的一个特性:
awk 会根据语境来给未定义的变量赋初始值
  1. ly5066113@ubuntu:~$ awk 'BEGIN{print a "" 1}'
  2. 1
  3. ly5066113@ubuntu:~$ awk 'BEGIN{print a + 1}'
  4. 1
复制代码
对于未定义的变量,如果要进行字符串操作,会被赋成空字符串 ""
如果要进行数学运算,会被赋成数字 0

现在我们看看上面的代码 ! a[$0] ++ 等价于 if(! a[$0] ++) print $0
对于首次出现的记录,a[$0]的值是未定义的,由于后面的 ++ 是数学计算,所以a[$0]会被赋值成数字0
也是由于 ++ 操作符,会先取值,再计算,所以对于第一行记录实际上是if(! 0) print $0
! 是取反,0 是假,! 0 就是真,那么就会执行后面的 print $0
对于后面出现的重复记录,a[$0] 经过 ++ 的计算已经变为 1、2、3 。。。
而 ! 1  ! 2  ! 3 ... 都为假,不会打印。

下面我们用黑哥的一段代码来深刻体会一下,用awk打印奇数行:
  1. ly5066113@ubuntu:~$ seq 10 | awk 'i=!i'
  2. 1
  3. 3
  4. 5
  5. 7
  6. 9
复制代码
你想明白了么?


四、NR 与 FNR 差在哪

NR与FNR在awk处理单个文件时是没有区别的,处理多个文件时才有区别,我们先看个例子:
  1. ly5066113@ubuntu:~$ awk '{print FILENAME,"NR="NR,"FNR="FNR,$0}' a.txt b.txt c.txt
  2. a.txt NR=1 FNR=1 a
  3. a.txt NR=2 FNR=2 b
  4. a.txt NR=3 FNR=3 c
  5. b.txt NR=4 FNR=1 d
  6. b.txt NR=5 FNR=2 e
  7. b.txt NR=6 FNR=3 f
  8. c.txt NR=7 FNR=1 g
  9. c.txt NR=8 FNR=2 h
  10. c.txt NR=9 FNR=3 i
复制代码
我们可以看到,NR是awk处理的总记录数,无论多少个文件,是一直累加的
而FNR是awk处理当前文件的记录数,当文件变化的时候是重新记数的

上面还有出现了一个变量FILENAME,这个变量的值就是awk当前处理的文件的文件名
这里我们还有几个变量需要了解:ARGV、ARGC、ARGIND
ARGV 是一个数组,它记录着命令行的所有参数的值
ARGC 是命令行参数的个数,(不包括-F、-v之类的awk参数)
ARGIND 是ARGV数组的索引值,从0到ARGC-1
当我们想去了解这些变量时,最简单并且最有效的方法就是print
  1. ly5066113@ubuntu:~$ awk 'BEGIN{for(i=0;i<ARGC;i++) print "ARGV["i"]="ARGV[i]}{print ARGV[ARGIND],ARGIND,ARGC,$0}' [abc].txt
  2. ARGV[0]=awk
  3. ARGV[1]=a.txt
  4. ARGV[2]=b.txt
  5. ARGV[3]=c.txt
  6. a.txt 1 4 a
  7. a.txt 1 4 b
  8. a.txt 1 4 c
  9. b.txt 2 4 d
  10. b.txt 2 4 e
  11. b.txt 2 4 f
  12. c.txt 3 4 g
  13. c.txt 3 4 h
  14. c.txt 3 4 i
复制代码
那么,ARGV[ARGIND]与FILENAME是否等价呢?
一般情况下,在awk处理文件时,两者是一样的
我们看看其他一些特殊的情况;
  1. ly5066113@ubuntu:~$ awk 'BEGIN{print FILENAME,ARGV[ARGIND]}'
  2. awk
  3. ly5066113@ubuntu:~$ awk 'BEGIN{getline;print FILENAME,ARGV[ARGIND],$0}'
  4. 123
  5. - awk 123
  6. ly5066113@ubuntu:~$ awk 'BEGIN{getline;print FILENAME,ARGV[ARGIND],$0}' a.txt
  7. a.txt a.txt a
  8. ly5066113@ubuntu:~$ awk 'BEGIN{getline<"a.txt";print FILENAME,ARGV[ARGIND],$0}'
  9. awk a
复制代码
我们可以看到,在任何情况下,ARGV[ARGIND]始终是有值的,而FILENAME则不一定
  1. FILENAME    The name of the current input file.  If no files are specified on the command line, the value of FILENAME is "-".  However, FILENAME is undefined  inside
  2.                    the BEGIN block (unless set by getline).
复制代码
下面我们用一个简单的例子来理解下上面的内容;
实现 head 命令的功能
我想这个问题大家一定都会:
  1. awk 'NR<=10'
复制代码
但这里我们希望是用awk处理多个文件,先来看看head处理多个文件的情况:
  1. ly5066113@ubuntu:~$ head [abc].txt
  2. ==> a.txt <==
  3. a
  4. b
  5. c

  6. ==> b.txt <==
  7. d
  8. e
  9. f

  10. ==> c.txt <==
  11. g
  12. h
  13. i
复制代码
下面我们用awk来达到这个效果:
  1. ly5066113@ubuntu:~$ awk 'FNR==1{if(NR>1) print "";print "==> "FILENAME" <=="}FNR<=10' [abc].txt
  2. ==> a.txt <==
  3. a
  4. b
  5. c

  6. ==> b.txt <==
  7. d
  8. e
  9. f

  10. ==> c.txt <==
  11. g
  12. h
  13. i
复制代码
让我们再深入考虑下,head在处理文件时,无论文件多大,速度都是很快的,awk是否也可以呢?
上面的代码当然不可以,因为awk会处理整个文件,文件越大,速度越慢。
单个文件时可以这样改写:
  1. awk '1;NR==10{exit}'
复制代码
多个文件时用exit就不行了,因为这样awk处理一个文件后就结束了,我们可以用nextfile
  1. awk 'FNR==1{if(NR>1) print "";print "==> "FILENAME" <=="}1;FNR==10{nextfile}' [abc].txt
复制代码
nextfile就是停止处理当前文件,开始处理下一个文件。

我们再来看一个例子:
每三个文件合并为一个大文件
http://bbs.chinaunix.net/viewthread.php?tid=1792571
帖子里的方法是用while read的方式实现的,下面给一个纯awk的方法:
  1. ly5066113@ubuntu:~$ awk 'FNR==1&&ARGIND%3==1{if(ARGIND>1){print s>f;s=""};f=sprintf("file%02d-%02d",ARGIND,ARGIND+2)}/^set/{print $0>f}/^plot/{$1=s?"":$1;s=s?s","$0:$0}END{print s>f}' file[0-9][0-9]
  2. ly5066113@ubuntu:~$ cat file01-03
  3. set arrow from 7,1633 to 8,1383
  4. set label "9575(100916104th)" at 6.5,1683
  5. set arrow from 7,1633 to 8,1383
  6. set label "9575(100916104th)" at 6.5,1683
  7. set arrow from 7,1633 to 8,1383
  8. set label "9575(100916104th)" at 6.5,1683
  9. plot "diff_029.file" with linespoints, "diff_029.file" with linespoints, "diff_029.file" with linespoints
  10. ly5066113@ubuntu:~$ cat file04-06
  11. set arrow from 7,1633 to 8,1385
  12. set label "9575(100916104th)" at 6.5,1685
  13. set arrow from 7,1633 to 8,1383
  14. set label "9575(100916104th)" at 6.5,1683
  15. set arrow from 7,1633 to 8,1383
  16. set label "9575(100916104th)" at 6.5,1683
  17. plot "diff_029.file" with linespoints, "diff_029.file" with linespoints, "diff_029.file" with linespoints
复制代码
awk处理多个文件,是不是没想象中那么复杂呢?


五、> 与 >> 差在哪

这里的>和>>是awk内部的,不要和shell本身的>和>>混淆。
  1. ly5066113@ubuntu:~$ awk '{print NR,$0}' a.txt > b.txt
  2. ly5066113@ubuntu:~$ cat b.txt
  3. 1 a
  4. 2 b
  5. 3 c
  6. ly5066113@ubuntu:~$ awk '{print NR,$0 > "b.txt"}' a.txt
  7. ly5066113@ubuntu:~$ cat b.txt
  8. 1 a
  9. 2 b
  10. 3 c
复制代码
第一句awk命令中的 > 就是shell本身的IO重定向,第二句awk命令中的 > 是awk内部的IO重定向
awk中的 > 和 >> 类似perl的文件句柄,只在首次打开文件时有区别:
  1. ly5066113@ubuntu:~$ rm b.txt
  2. ly5066113@ubuntu:~$ awk '{print NR,$0 > "b.txt"}' a.txt
  3. ly5066113@ubuntu:~$ cat b.txt
  4. 1 a
  5. 2 b
  6. 3 c
  7. ly5066113@ubuntu:~$ rm b.txt
  8. ly5066113@ubuntu:~$ awk '{print NR,$0 >> "b.txt"}' a.txt
  9. ly5066113@ubuntu:~$ cat b.txt
  10. 1 a
  11. 2 b
  12. 3 c
  13. ly5066113@ubuntu:~$ awk '{print NR,$0 > "b.txt"}' a.txt
  14. ly5066113@ubuntu:~$ cat b.txt
  15. 1 a
  16. 2 b
  17. 3 c
  18. ly5066113@ubuntu:~$ awk '{print NR,$0 >> "b.txt"}' a.txt
  19. ly5066113@ubuntu:~$ cat b.txt
  20. 1 a
  21. 2 b
  22. 3 c
  23. 1 a
  24. 2 b
  25. 3 c
复制代码
如果文件不存在,那么 > 和 >> 是一样的
如果文件已经存在,> 会覆盖原文件,>> 则是追加

我们看到,在打开文件后,awk会一直向文件里追加记录,那么可以在awk里关闭文件么?
这时我们就需要用到 close
  1. ly5066113@ubuntu:~$ awk '{print NR,$0 > "b.txt";close("b.txt")}' a.txt
  2. ly5066113@ubuntu:~$ cat b.txt
  3. 3 c
复制代码
每次写入后都关闭文件,那么下次写入时就又重新打开文件
而每次打开又是覆盖的方式,这样b.txt里最后就只剩下a.txt的最后一行记录

说到awk中的IO就不得不提 getline
  1. getline               Set $0 from next input record; set NF, NR, FNR.
  2. getline <file         Set $0 from next record of file; set NF.
  3. getline var           Set var from next input record; set NR, FNR.
  4. getline var <file     Set var from next record of file.
  5. command | getline [var]
  6.                       Run command piping the output either into $0 or var, as above.
复制代码
getline的用法很灵活,可以从awk当前处理的文件中获取下一行记录
也可以从外部的文件或者管道中获取记录,每次只取一行,赋给$0或者变量var
先来看个简单的例子,实现 grep -A1
  1. ly5066113@ubuntu:~$ seq 10 | grep -A1 5
  2. 5
  3. 6
  4. ly5066113@ubuntu:~$ seq 10 | awk '/5/{print;getline;print}'
  5. 5
  6. 6
复制代码
再看个例子:
有没有将两个输出或者说变量上每列分别合在一起的方法
http://bbs3.chinaunix.net/viewthread.php?tid=1752341
  1. $ var1='a
  2. > b
  3. > c
  4. > d'
  5. $ var2='A
  6. > B
  7. > C
  8. > D'
  9. $ export var2
  10. $ echo "$var1" | awk '{"echo \042$var2\042"|getline var2;print $1""var2}'
  11. aA
  12. bB
  13. cC
  14. dD
复制代码
你看懂了么?


评分

参与人数 5可用积分 +26 收起 理由
blackold + 5 好。学习! 太穷了,最多只能5块。
好看的附件 + 2 经典原创
liaosnet + 4 原创·
bbgg1983 + 5 这个我喜欢
expert1 + 10 辛苦了,节日好!

查看全部评分

论坛徽章:
23
15-16赛季CBA联赛之吉林
日期:2017-12-21 16:39:27白羊座
日期:2014-10-27 11:14:37申猴
日期:2014-10-23 08:36:23金牛座
日期:2014-09-30 08:26:49午马
日期:2014-09-29 09:40:16射手座
日期:2014-11-25 08:56:112015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:49:0315-16赛季CBA联赛之山东
日期:2017-12-21 16:39:1915-16赛季CBA联赛之广东
日期:2016-01-19 13:33:372015亚冠之山东鲁能
日期:2015-10-13 09:39:062015亚冠之西悉尼流浪者
日期:2015-09-21 08:27:57
发表于 2010-09-23 13:26 |显示全部楼层
今天先写到这里,后续还会补充。

论坛徽章:
0
发表于 2010-09-23 13:28 |显示全部楼层
果断沙发
随便瞎扯下最后那个
seq 10 | awk 'i=!i'
因为一开始i=0
在第一行的时候 i=!i于是i=1 打印
第二行的时候 i=!i于是i=0不 打印
如此往复

论坛徽章:
23
15-16赛季CBA联赛之吉林
日期:2017-12-21 16:39:27白羊座
日期:2014-10-27 11:14:37申猴
日期:2014-10-23 08:36:23金牛座
日期:2014-09-30 08:26:49午马
日期:2014-09-29 09:40:16射手座
日期:2014-11-25 08:56:112015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:49:0315-16赛季CBA联赛之山东
日期:2017-12-21 16:39:1915-16赛季CBA联赛之广东
日期:2016-01-19 13:33:372015亚冠之山东鲁能
日期:2015-10-13 09:39:062015亚冠之西悉尼流浪者
日期:2015-09-21 08:27:57
发表于 2010-09-23 13:32 |显示全部楼层
回复 3# lkk2003rty


呵呵,一开始 i=0 是如何得到的?

论坛徽章:
0
发表于 2010-09-23 13:53 |显示全部楼层
本帖最后由 justlooks 于 2010-09-23 14:05 编辑

扫描第1行
i = ! i 第1个未定义 翻过来就是 i =1

打印偶数行
awk 'i++%2'

论坛徽章:
16
IT运维版块每日发帖之星
日期:2015-08-24 06:20:00综合交流区版块每日发帖之星
日期:2015-10-14 06:20:00IT运维版块每日发帖之星
日期:2015-10-25 06:20:00IT运维版块每日发帖之星
日期:2015-11-06 06:20:00IT运维版块每日发帖之星
日期:2015-12-10 06:20:00平安夜徽章
日期:2015-12-26 00:06:302016猴年福章徽章
日期:2016-02-18 15:30:34IT运维版块每日发帖之星
日期:2016-04-15 06:20:00IT运维版块每日发帖之星
日期:2016-05-21 06:20:00综合交流区版块每日发帖之星
日期:2016-08-16 06:20:002015七夕节徽章
日期:2015-08-21 11:06:17IT运维版块每日发帖之星
日期:2015-08-14 06:20:00
发表于 2010-09-23 14:04 |显示全部楼层
前排就坐围观,留名先,TIM哥辛苦了。节日快乐!

论坛徽章:
0
发表于 2010-09-23 14:05 |显示全部楼层
牛逼之人  先标记下  慢慢看 我被这个awk  折磨得伤心了

我不知道到底是不是该好好学,因为目前时间紧,那么想先学perl

论坛徽章:
16
IT运维版块每日发帖之星
日期:2015-08-24 06:20:00综合交流区版块每日发帖之星
日期:2015-10-14 06:20:00IT运维版块每日发帖之星
日期:2015-10-25 06:20:00IT运维版块每日发帖之星
日期:2015-11-06 06:20:00IT运维版块每日发帖之星
日期:2015-12-10 06:20:00平安夜徽章
日期:2015-12-26 00:06:302016猴年福章徽章
日期:2016-02-18 15:30:34IT运维版块每日发帖之星
日期:2016-04-15 06:20:00IT运维版块每日发帖之星
日期:2016-05-21 06:20:00综合交流区版块每日发帖之星
日期:2016-08-16 06:20:002015七夕节徽章
日期:2015-08-21 11:06:17IT运维版块每日发帖之星
日期:2015-08-14 06:20:00
发表于 2010-09-23 14:12 |显示全部楼层
本帖最后由 expert1 于 2010-09-23 16:39 编辑

借宝地问个问题。
x    abcd
y    0,1
z    a,b,c

变成:
x abcd y 0 z a
x abcd y 0 z b
x abcd y 0 z c
x abcd y 1 z a
x abcd y 1 z b
x abcd y 1 z c
===================
规则:y (0/1) z (a/b/C)有6种情况

实际上就是第一行不变,然后2,3行的$2组合有3x2=6种。当然文件内容再加一行的话继续3x2x? (?是下一行第一列的值的个数了。实际上就是一个组合了。)

我的思路是,NR==1记录第一行,NR>1,a[$1]=$2,遍历a然后split{a,c)}遍历打印,但是输出顺序不符合。

当然直接split,2个for足以搞掂这个问题。但是当行数很多的时候,那要多少个for呀,所以有无好的办法,按照我的那个思路或别的?

论坛徽章:
16
IT运维版块每日发帖之星
日期:2015-08-24 06:20:00综合交流区版块每日发帖之星
日期:2015-10-14 06:20:00IT运维版块每日发帖之星
日期:2015-10-25 06:20:00IT运维版块每日发帖之星
日期:2015-11-06 06:20:00IT运维版块每日发帖之星
日期:2015-12-10 06:20:00平安夜徽章
日期:2015-12-26 00:06:302016猴年福章徽章
日期:2016-02-18 15:30:34IT运维版块每日发帖之星
日期:2016-04-15 06:20:00IT运维版块每日发帖之星
日期:2016-05-21 06:20:00综合交流区版块每日发帖之星
日期:2016-08-16 06:20:002015七夕节徽章
日期:2015-08-21 11:06:17IT运维版块每日发帖之星
日期:2015-08-14 06:20:00
发表于 2010-09-23 14:16 |显示全部楼层
回复 2# ly5066113


    TIM哥节日快乐,看下我楼上的那个问题,有无好的思路呀?谢谢了!

论坛徽章:
28
ChinaUnix元老
日期:2015-02-02 08:55:392017金鸡报晓
日期:2017-01-10 15:13:29CU十四周年纪念徽章
日期:2018-08-29 22:12:2715-16赛季CBA联赛之深圳
日期:2018-09-20 12:21:09
发表于 2010-09-23 14:21 |显示全部楼层
学习
Tim哥辛苦了
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

基于案例的 SQL 优化实战训练营

讲师:中电福富特级专家梁敬彬,参与本次课程培训,你将收获:
1. 能编写出较为高效的 SQL;
2. 能解决70%以上的数据库常见优化问题;
3. 能得到老师提供的高效的相关工具和解决方案;
4. 能举一反三,收获不仅仅是 SQL 优化。
现在购票享受8.8折优惠!
----------------------------------------
优惠时间:2019年3月20日前

大会官网>>
  

北京盛拓优讯信息技术有限公司. 版权所有 16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122
中国互联网协会会员  联系我们:huangweiwei@it168.com
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP