免费注册 查看新帖 |

Chinaunix

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

awk 中的 $1=$1 [复制链接]

论坛徽章:
0
发表于 2012-03-17 00:45 |显示全部楼层
echo '1 2 3 4' | awk '{OFS="\n"; printf $0}'
1 2 3 4


echo '1 2 3 4' | awk '{OFS="\n"; $1=$1; printf $0}'
1
2
3
4

y?

论坛徽章:
1
摩羯座
日期:2014-12-29 15:59:36
发表于 2012-03-17 00:48 |显示全部楼层
8.$1=$1 是用来激活$0的重新赋值,也就是说 字段$1...和字段数NF的改变会促使awk重新计算$0的值,通常是在改变OFS后而需要输出$0时这样做

    echo "A B C D" | awk '{OFS="|";print $0;$1=$1;print $0;}'
    A B C D
    A|B|C|D
   
    即使OFS放在BEGIN里,也没有用
    echo "A B C D" | awk 'BEGIN{OFS="|"}{print $0;$1=$1;print $0;}'
    A B C D
    A|B|C|D

   $0=$0 刚好相反, 修改$0的值可以促使awk重新计算字段$1...和字段数NF的的值,通常是在改变FS后而需要输出$1...或者NF时这样做

    echo "A|B|C|D" | awk '{FS="|";print $1,NF;$0=$0;print $1,NF}'
    A|B|C|D 1
    A 4
   
    不过把修改FS放在BEGIN里,就没必要$0=$0了
    echo "A|B|C|D" | awk 'BEGIN{FS="|"}{print $1,NF;$0=$0;print $1,NF}'
    A 4
    A 4
   
其实,在awk源码中.重新计算$0的值的函数名叫rebuild_record,重构记录的意思.默认情况下.这个函数是不可能执行的.因为$0是直接读入的.$1=$1等修改字段的行为会触发awk执行这个函数
重新计算$1...的值的函数名叫reset_record,重新分割记录到字段的意思.默认情况下.这个函数只在处理完当前行,读入下一行之前执行.中途是不会执行的.$0=$0等修改记录的行为会触发awk执行这个函数
通过在源码中添加一行标记重新编译awk.可以查看awk到底什么时候运行了这两个函数.

rebuild_record
  • echo "A B C D" | awk '{print $0;OFS="|";print "OFS=\"|\"";print $0;print "$1=$1";$1=$1;print $0;}'
  • -----------reset_record-----------             #读入行之前,执行reset_record,把$0拆分开赋值给$1...
  • A B C D                                         #$0为读入的值
  • OFS="|"                                        #改变OFS
  • A B C D                                         #没有触发rebuild_record重构$0,$0仍为读入的值.
  • $1=$1                                           #执行$1=$1,
  • ----------rebuild_record------------            #awk不管$1是否真的改变,执行rebuild_record.
  • A|B|C|D                                         #$0的值成为各个字段和ORS计算出的值

复制代码
reset_record
  • echo "A|B|C|D" | awk '{print $1,NF;print "FS=\"|\"";FS="|";print $1,NF;print "$0=$0";$0=$0;print $1,NF}'
  • -----------reset_record-----------              #读入行之前,执行reset_record,把$0拆分开赋值给$1...
  • A|B|C|D 1                                        #$1为刚才计算的值
  • FS="|"                                             #改变FS
  • A|B|C|D 1                                        #没有触发reset_record重构$1和NF,仍为第一次计算的值.
  • $0=$0                                             #执行$0=$0
  • -----------reset_record-----------              #awk不管$0是否真的改变,执行reset_record.
  • A 4                                                   #$1和NF的值成为重新计算出的值

复制代码

论坛徽章:
0
发表于 2012-03-17 01:42 |显示全部楼层
顶2楼

论坛徽章:
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
发表于 2012-03-17 08:24 |显示全部楼层

  1. Advanced Notes: Changing FS Does Not Affect the Fields

  2. According to the POSIX standard, awk is supposed to behave as if each record is split into fields at the time it is read. In particular, this means that if you change the value of FS after a record is read, the value of the fields (i.e., how they were split) should reflect the old value of FS, not the new one.

  3. However, many older implementations of awk do not work this way. Instead, they defer splitting the fields until a field is actually referenced. The fields are split using the current value of FS! (d.c.) This behavior can be difficult to diagnose. The following example illustrates the difference between the two methods. (The sed21 command prints just the first line of /etc/passwd.)

  4.      sed 1q /etc/passwd | awk '{ FS = ":" ; print $1 }'

  5. which usually prints:

  6.      root

  7. on an incorrect implementation of awk, while gawk prints something like:

  8.      root:nSijPlPhZZwgE:0:0:Root:/:
复制代码
这种作法算是对标准的一种补偿吧

论坛徽章:
1
辰龙
日期:2014-05-22 11:38:58
发表于 2012-03-17 08:43 |显示全部楼层
回复 2# ziyunfei


    顶,求资料出处。

论坛徽章:
33
ChinaUnix元老
日期:2015-02-02 08:55:39CU十四周年纪念徽章
日期:2019-08-20 08:30:3720周年集字徽章-周	
日期:2020-10-28 14:13:3020周年集字徽章-20	
日期:2020-10-28 14:04:3019周年集字徽章-CU
日期:2019-09-08 23:26:2519周年集字徽章-19
日期:2019-08-27 13:31:262016科比退役纪念章
日期:2022-04-24 14:33:24
发表于 2012-03-17 09:15 |显示全部楼层

论坛徽章:
0
发表于 2012-03-17 09:38 |显示全部楼层
SS兄(@yinyuemi)写过一篇文章:
http://bbs.chinaunix.net/thread-2309494-1-1.html
请看第四点!

论坛徽章:
3
2015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:51:162015年亚洲杯之阿曼
日期:2015-04-07 20:00:59
发表于 2012-03-17 10:46 |显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽

论坛徽章:
1
摩羯座
日期:2014-12-29 15:59:36
发表于 2012-03-17 15:17 |显示全部楼层
winway1988 发表于 2012-03-17 08:43
回复 2# ziyunfei


http://bbs.chinaunix.net/thread-2319120-1-1.html

11年shell大赛第八题
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP