我有一个包含以下数据结构的 csv:
1111,2222,3333,4444,5555,6666,7777,2017-1-5 1:07:09,2017-1-5 1:11:53
1111,2222,3333,4444,5555,6666,7777,2017-11-25 19:57:17,2017-11-25 19:58:54
我想显示日期月份和日期始终为 2 位数字。我还希望时间小时字段始终为 2 位数。
如果月/日/小时字段只有一个数字,如上面的示例行所示,则基本上添加前导零。
使用 awk,我将如何实现以下结果:
1111,2222,3333,4444,5555,6666,7777,2017-01-05 01:07:09,2017-01-05 01:11:53
1111,2222,3333,4444,5555,6666,7777,2017-11-25 19:57:17,2017-11-25 19:58:54
一个很好的文本处理工具是awk。以下示例在 FreeBSD 11.1 上使用普通标准 awk。如果您更喜欢 GNU awk,@RomanPerekhrest 在另一个答案中有一个优雅的解决方案。
您的输入以逗号分隔。因此,我们
awk
使用-F,
参数调用。print
然后我们可以使用该语句打印出列。$1
是第一列。$2
是第二列。这为我们提供了每行的第 8 列。
这就是您要操作的日期字段。我们可以将其作为脚本的一部分进行,而不是使用命令行参数设置分隔符。FS 用于输入分隔符,OFS 用于输出分隔符。
在处理日期时,我通常更喜欢使用
date
util 来确保正确处理它们。如果我使用常规或 GNU awk,我无需担心。此外,如果日期解析不正确,我会遇到很大的失败。有趣的参数是:
因此,如果我们在某个日期运行它:
然后我们可以将它与 awk 结合起来。注意引号是如何转义的。这可能是初学者最大的绊脚石。
系统调用似乎是正确的——但不幸的是,它只允许我们捕获返回码并直接打印到输出。为了避免这种情况,我们使用
cmd | getline
模式。下面的简单示例会将当前日期读入 mydate:我们使用
BEGIN
关键字,因为我们没有输入这个简单的例子。所以让我们扩展一下:
我们可以把它折叠成一个单行:
这给了我输出:
附录
由于这里的目的是学习好习惯,我最好更新这个答案。重复代码是一个坏习惯。当您开始这样做时,您应该将事物拆分为一个函数。您会注意到下面的代码立即变得更具可读性。
养成这样的习惯,你会注意到以后引入错误处理会变得多么容易。
如果您有 GNU awk,您可以将最终字段转换为空格分隔的datespec字符串,然后根据需要使用以下命令重新格式化
strftime
:请参阅GNU awk 用户指南:时间函数
简单的 GNU
awk
解决方案:gsub(/\<[0-9]\>/, "0&", <field>)
- 仅替换/补充日期时间字符串 中的独立单个数字:\<
和\>
- 是单词边界&
- 代表正则表达式匹配的精确子字符串输出:
它替换所有单独的数字,这些数字前面是
[-: ]
字符,后面是任何非单词字符。这个解决方案简短而简单,但容易出错,因为它不检查日期模式,只是将前导零添加到所有单独的数字中,这符合
[-: ][0-9]\b
模式(\b
- 匹配单词边界)。但作为变体。输入
输出
dateutils包有处理时间/日期格式数据细节的代码。
生产:
在这样的系统上:
dconv 的一些细节:
最良好的祝愿......干杯,drl