免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 3628 | 回复: 19
打印 上一主题 下一主题

三个awk问题的讨论 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2012-05-02 13:17 |只看该作者 |倒序浏览
问题1: 关于awk中的操作符"in"在for中应用
  1. # echo "23 sc 39 eu 2 47"|awk '{for(i=1;i<=NF;i++)arry[$i]=$i}END{for(item in arry)printf "%-4.3s| %s\n",item,arry[item]}'
  2. 47 | 47
  3. 39 | 39
  4. sc | sc
  5. eu | eu
  6. 23 | 23
  7. 2 | 2
复制代码
  1. # echo "23 sc 39 eu 2 47"|awk '{for(i=1;i<=NF;i++)arry[i]=$i}END{for(item in arry)printf "%-4.3s| %s\n",item,arry[item]}'
  2. 4 | eu
  3. 5 | 2
  4. 6 | 47
  5. 1 | 23
  6. 2 | sc
  7. 3 | 39
复制代码
Q: 类似这种索引下标是非常规顺序数字的情况,for(item in arry)是如何处理输出先后顺序的?
    另外,如果是数字下标,输出顺序如何调整为正常顺序?  

=======================================================================================

问题2: 关于awk内部变量"FS"定义对字段数的影响
  1. # echo -e "word1 * word2\n word3 word4"|awk 'BEGIN{FS="[[:space:]]"}{for(i=1;i<=NF;i++)printf $i"-";printf " |"NF"\n"}'
  2. word1-*---word2- |5
  3. -word3-word4- |3
  4. # echo -e "word1 * word2\n word3 word4"|awk 'BEGIN{FS=" "}{for(i=1;i<=NF;i++)printf $i"-";printf " |"NF"\n"}'
  5. word1-*-word2- |3
  6. word3-word4- |2
  7. # echo -e "word1-*---word2\n word3-word4"|awk 'BEGIN{FS="-"}{for(i=1;i<=NF;i++)printf $i"/";printf " |"NF"\n"}'
  8. word1/*///word2/ |5
  9. word3/word4/ |2
复制代码
Q: 为什么指定"FS=[[:space:]]"或"FS=[[:blanck:]]"得到的字段与指定FS=" "得到的字段数不一致呢?
    换句话说就是为什么在"FS=[[:space:]]"或"FS=[[:blanck:]]"时awk没有自动压缩多余空白符?即使换成其它分隔符也是一样,好像awk对空白符会特别照顾

=======================================================================================

问题3: 关于awk对于跨行字段的处理
  1. # cat file_test
  2. word1 word2
  3. word3 word4

  4. word3 word4
  5. word5 word6

  6. word5 word6
  7. # cat file_test |awk 'BEGIN{RS="";FS="o"}{for(i=1;i<=NF;i++)printf $i"|";printf "\n" }'
  8. w|rd1 w|rd2|w|rd3 w|rd4|
  9. w|rd3 w|rd4|w|rd5 w|rd6|
  10. w|rd5 w|rd6|
复制代码
Q: 为什么这里定义了字段分隔符为"o",但还是将第一行的"rd2"与第二行的"w"分开了?


希望各位大侠能给点提示,集思广益,大家讨论讨论。。。^_^

论坛徽章:
145
技术图书徽章
日期:2013-10-01 15:32:13戌狗
日期:2013-10-25 13:31:35金牛座
日期:2013-11-04 16:22:07子鼠
日期:2013-11-18 18:48:57白羊座
日期:2013-11-29 10:09:11狮子座
日期:2013-12-12 09:57:42白羊座
日期:2013-12-24 16:24:46辰龙
日期:2014-01-08 15:26:12技术图书徽章
日期:2014-01-17 13:24:40巳蛇
日期:2014-02-18 14:32:59未羊
日期:2014-02-20 14:12:13白羊座
日期:2014-02-26 12:06:59
2 [报告]
发表于 2012-05-02 15:59 |只看该作者
本帖最后由 jason680 于 2012-05-02 15:59 编辑

回复 1# chaogle

Q:...如果是数字下标,输出顺序如何调整为正常顺序?
$ echo "23 sc 39 eu 2 47"|awk '{for(n=0;n++<NF;)a[n]=$n}END{for(n=0;n++<NF;)print n"|"a[n]}'
1|23
2|sc
3|39
4|eu
5|2
6|47
   

论坛徽章:
3
水瓶座
日期:2014-03-25 17:08:042015亚冠之塔什干棉农
日期:2015-08-10 10:45:122015亚冠之萨济拖拉机
日期:2015-08-13 16:05:24
3 [报告]
发表于 2012-05-02 17:33 |只看该作者
我好奇的是问题3,为什么输出会是4个word或者说是用空格隔开的三个域呢?原先是每行两个域,现在变成了三个,这是什么原因呢?

论坛徽章:
8
摩羯座
日期:2014-11-26 18:59:452015亚冠之浦和红钻
日期:2015-06-23 19:10:532015亚冠之西悉尼流浪者
日期:2015-08-21 08:40:5815-16赛季CBA联赛之山东
日期:2016-01-31 18:25:0515-16赛季CBA联赛之四川
日期:2016-02-16 16:08:30程序设计版块每日发帖之星
日期:2016-06-29 06:20:002017金鸡报晓
日期:2017-01-10 15:19:5615-16赛季CBA联赛之佛山
日期:2017-02-27 20:41:19
4 [报告]
发表于 2012-05-02 17:41 |只看该作者
回复 3# su8610


    因为文件里有\n

论坛徽章:
3
水瓶座
日期:2014-03-25 17:08:042015亚冠之塔什干棉农
日期:2015-08-10 10:45:122015亚冠之萨济拖拉机
日期:2015-08-13 16:05:24
5 [报告]
发表于 2012-05-02 18:26 |只看该作者
# cat file_test
word1 word2
word3 word4

word3 word4
word5 word6

word5 word6
# cat file_test |awk 'BEGIN{RS="";FS="o"}{for(i=1;i<=NF;i++)printf $i"|";printf "\n" }'
w|rd1 w|rd2|w|rd3 w|rd4|
w|rd3 w|rd4|w|rd5 w|rd6|
w|rd5 w|rd6|
是的,有\n换行,但是换行不应该是在原来的行后换行么?也就是说我不能理解的是原来的换行符怎么不见了而在新的位置插入了换行符?回复 4# waker


   

论坛徽章:
3
水瓶座
日期:2014-03-25 17:08:042015亚冠之塔什干棉农
日期:2015-08-10 10:45:122015亚冠之萨济拖拉机
日期:2015-08-13 16:05:24
6 [报告]
发表于 2012-05-02 18:30 |只看该作者
而且这每一行的NF应该是2啊,那应该是在两个域后面加一个换行符才对啊

论坛徽章:
0
7 [报告]
发表于 2012-05-02 18:51 |只看该作者
回复 2# jason680

兄弟,感谢你的回复。
但是我还是有点疑惑,关于for(item in arry)的循环中awk是如何处理输出的先后顺序的。

弄清楚这个又是在处理字非连续下标数组时就能准确调用数组元素了,即便不是字符串下标
最初的连续数字索引,由于删除数组成员或间断赋值导致数组成员下标索引不连续,此时再使用"for(i=1;i<=NF;i++)"的结果就不太灵活了

其实就是想知道用什么办法可以让for(item in arry)的输出顺序正常化,因为它的优势是不用我自己检测arry数组变量中到底装了多少成员,但缺点是输出的顺序跟预期的不一样
比如成员是: 1 2 3 6 8 10 12 20 34
输出结果确是:
  1. # echo "1 2 3 6 8 10 12 20 34"|awk '{for(i=1;i<=NF;i++){var=var"x";arry[$i]=var}}END{for(item in arry)print item"\t"arry[item]}'
  2. 6        xxxx
  3. 8        xxxxx
  4. 10        xxxxxx
  5. 20        xxxxxxxx
  6. 12        xxxxxxx
  7. 1        x
  8. 2        xx
  9. 34        xxxxxxxxx
  10. 3        xxx
复制代码
难道只能自己写冒泡法来给它排序吗?
  1. # echo "1 2 3 6 8 10 12 20 34"|awk '{for(i=1;i<=NF;i++){var=var"x";arry[$i]=var}}END{for(item in arry)print item"\t"arry[item]}'|awk '{arry_o[NR]=$1":"$2}END{n=length(arry_o);for(i=1;i<n;i++){for(j=i+1;j<=n;j++){tmp=arry_o[i];var1=strtonum(arry_o[i]);var2=strtonum(arry_o[j]);if(var1>var2){arry_o[i]=arry_o[j];arry_o[j]=tmp}}}for(i=1;i<=n;i++)print arry_o[i]}'
  2. 1:x
  3. 2:xx
  4. 3:xxx
  5. 6:xxxx
  6. 8:xxxxx
  7. 10:xxxxxx
  8. 12:xxxxxxx
  9. 20:xxxxxxxx
  10. 34:xxxxxxxxx
复制代码

论坛徽章:
0
8 [报告]
发表于 2012-05-02 19:45 |只看该作者
对于问题1,我找到了一个替代for(item in arry)循环输出数组的办法,这里跟大家分享一下:
受网友 “dahaoshanhe” 的启发
非数字索引下标数组输出
  1. #  echo "1 2 3 6 8 10 12 20 34"|awk '{for(i=1;i<=NF;i++){var=var"x";arry[$i]=var}}END{count=asorti(arry,d);for(i=1;i<=count;i++)d[i]=strtonum(d[i]);asort(d);for(i=1;i<=count;i++)print d[i]"\t"arry[d[i]]}'
  2. 1        x
  3. 2        xx
  4. 3        xxx
  5. 6        xxxx
  6. 8        xxxxx
  7. 10        xxxxxx
  8. 12        xxxxxxx
  9. 20        xxxxxxxx
  10. 34        xxxxxxxxx
复制代码
这样不仅达到了数组成员全部输出的效果,而起还依照数组下标大小顺序排列后输出,效果不错 !

论坛徽章:
8
摩羯座
日期:2014-11-26 18:59:452015亚冠之浦和红钻
日期:2015-06-23 19:10:532015亚冠之西悉尼流浪者
日期:2015-08-21 08:40:5815-16赛季CBA联赛之山东
日期:2016-01-31 18:25:0515-16赛季CBA联赛之四川
日期:2016-02-16 16:08:30程序设计版块每日发帖之星
日期:2016-06-29 06:20:002017金鸡报晓
日期:2017-01-10 15:19:5615-16赛季CBA联赛之佛山
日期:2017-02-27 20:41:19
9 [报告]
发表于 2012-05-02 19:54 |只看该作者
su8610 发表于 2012-05-02 18:30
而且这每一行的NF应该是2啊,那应该是在两个域后面加一个换行符才对啊

你认为的“应该”与大家的约定不同而已,过两天你和大家统一以后这个问题自然就解决了

论坛徽章:
145
技术图书徽章
日期:2013-10-01 15:32:13戌狗
日期:2013-10-25 13:31:35金牛座
日期:2013-11-04 16:22:07子鼠
日期:2013-11-18 18:48:57白羊座
日期:2013-11-29 10:09:11狮子座
日期:2013-12-12 09:57:42白羊座
日期:2013-12-24 16:24:46辰龙
日期:2014-01-08 15:26:12技术图书徽章
日期:2014-01-17 13:24:40巳蛇
日期:2014-02-18 14:32:59未羊
日期:2014-02-20 14:12:13白羊座
日期:2014-02-26 12:06:59
10 [报告]
发表于 2012-05-02 20:27 |只看该作者
回复 7# chaogle

try it and easy to use with asorti
$ echo "1 2 3 6 8 10 12 20 34"|awk '{for(n=1;n<=NF;n++){v=v"x";a[sprintf("%03d",$n)]=v}}END{c=asorti(a,b);for(n=1;n<=c;n++)print b[n]"\t"a[b[n]]}'
001        x
002        xx
003        xxx
006        xxxx
008        xxxxx
010        xxxxxx
012        xxxxxxx
020        xxxxxxxx
034        xxxxxxxxx


   
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP