A,B,C,D
1,30/07/2014,data_n/a,data_n/a
2,30/07/2014,22/02/2018,data_n/a
3,26/02/2015,22/12/2016,28/07/2017
我想一次性将所有日期转换为纪元格式。我尝试让以下代码运行,但它只输出 2 列。
gawk -F, '{for (i=1; i<=4; i++) split($i,date,"/");
$i=mktime(date[3] " " date[2] " " date[1] " " "00 00 00");
printf $i","; if (NF >=1 ) print $1; }'
我究竟做错了什么?
答案1
我究竟做错了什么?
您正在构建for
这样的循环:
for (i=1; i<=4; i++) split($i,date,"/")
我的意思是全部的循环。后面的代码不属于循环。循环结束后, 的最后一个值i
仍然存在,并且date
来自最后一个split
。
最有可能的是,您希望在 之前(或之后)结束循环if (NF >=1 ) print $1
。因为您似乎对 的处理$1
方式不同或许您想从哪里开始i=2
。由于不清楚输出应该是什么,我不确定您真正想要的确切程序。可能是这样的:
gawk -F, '{for (i=2; i<=4; i++) {split($i,date,"/");
$i=mktime(date[3] " " date[2] " " date[1] " " "00 00 00");
printf $i","} if (NF >=1 ) print $1; }'
无论如何,我认为这里最大的问题是
for ( … ) single_command
你需要
for ( … ) { multiple; commands }
答案2
在编写程序时格式化可能会有所帮助 - 这样您可能会看到哪里出了问题:
{
for (i=1; i<=4; i++)
split($i,date,"/");
$i=mktime(date[3] " " date[2] " " date[1] " " "00 00 00");
printf $i",";
if (NF >=1 )
print $1;
}
- 现在应该清楚的是,
$i=mktime()
andprintf
语句在for
循环之外
以下是使用 GNU 的另一种方法awk
:
$ cat script.awk
BEGIN { FS=OFS="," }
FNR > 1 {
for (i=2; i <= NF; i++)
if ($i ~ /^([[:digit:]]+\/){2}[[:digit:]]{4}$/) {
split($i, date, "/")
$i = mktime(date[3]" "date[2]" "date[1]" 0 0 0")
}
}
1
$ awk -f script.awk file
A,B,C,D
1,1406642400,data_n/a,data_n/a
2,1406642400,1519221600,data_n/a
3,1424872800,1482328800,1501164000
- 用作
,
输入和输出字段分隔符 - 在线数字
1
大于文件:- 循环
i
从2
到NF
- 如果该字段
$i
看起来像日期:- 拆分成组件
- 将结果指定
mktime()
为该字段的新值
- 循环
- 打印每一行
如果输入文件中的日期是 UTC,则添加utc 标志到mktime()
:
mktime(date[3]" "date[2]" "date[1]" 0 0 0", 1)