根据时间戳列合并并附加日期和时间列

根据时间戳列合并并附加日期和时间列

我有一个 csv 文件,其中包含示例数据条目,如下所示:

Timestamp,data1,data2
2018 07 16 13:00:00,23,45
2018 07 16 13:10:00,23,45
2018 07 16 13:20:00,23,45
2018 07 16 13:30:00,23,45
2018 07 16 13:50:00,23,45
2018 07 16 14:20:00,23,45
2018 07 16 14:40:00,23,45
2018 07 16 14:50:00,23,45
2018 07 16 15:10:00,23,45
2018 07 16 17:50:00,23,45
2018 07 16 18:10:00,23,45
2018 07 17 10:10:00,23,45
2018 07 18 13:20:00,23,45
2018 07 19 13:30:00,23,45

我想做的是创建其他两列Date& Hour。该Date列将包含日期,并且该Hour列将包含捕获数据的所有小时。例如,根据上面的数据,我想要以下输出(同一文件,只需添加额外的 2 列):

Date,Hour
2018 07 16,13
2018 07 16,14
2018 07 16,15
2018 07 16,17
2018 07 16,18
2018 07 17,10
2018 07 18,13
2018 07 19,13

例如,如果 2018 年 07 月 16 日的 13 小时(无论是 1 个还是多个)有条目,则仅列出相应的日期和 13 小时一次,然后继续处理具有不同小时的条目,直到日期发生变化。并重复该过程。

请注意,该文件在多天内有许多条目(100000+),一小时内捕获的数据数量各不相同,如上所述。我该如何解决这个问题?我希望我的解释足够清楚。

答案1

使用awk

awk 'BEGIN{ OFS=FS="," }
  NR==1{ print "Date", "Hour"; next }
  {
    $0=substr($1, 1, 10) FS substr($1, 12, 2)
    if ($0 == prev) next  # skip to next record if record equals prev
    prev=$0               # remember record
  }
  1                       # print record
' file

因此,日期字符串由从第一个字段的位置 1 开始的前 10 个字符组成,而小时是从从位置 12 开始的 2 个字符中提取的。

如果先前记住的记录不同,则这两个值加上字段分隔符 ( FS) 都会分配给记录 ( ) 并打印。$0

答案2

sortuniq可以为您提供问题中显示的输出示例。

$ sed -e 's/Timestamp.*/Date,Hour/; s/ \(..\):.*/,\1/' file.csv  | uniq
Date,Hour
2018 07 16,13
2018 07 16,14
2018 07 16,15
2018 07 16,17
2018 07 16,18
2018 07 17,10
2018 07 18,13
2018 07 19,13

但是,您还说过您希望将这两个新字段附加到当前输入行。这对我来说没有多大意义,因为这样您最终会在每行中重复出现日期和时间(它们已经位于时间戳字段中每行的开头)。

以下内容并不完全是您所要求的,但在我看来是一种改进。

它不是将日期和时间附加到每行的末尾,而是只是将sed现有的时间戳字段转换为日期和时间字段。 thenuniq用于消除重复行。

$ sed -e 's/Timestamp/Date,Hour/; s/ \(..\):[^,]*,/,\1,/' file.csv  | uniq
Date,Hour,data1,data2
2018 07 16,13,23,45
2018 07 16,14,23,45
2018 07 16,15,23,45
2018 07 16,17,23,45
2018 07 16,18,23,45
2018 07 17,10,23,45
2018 07 18,13,23,45
2018 07 19,13,23,45

这假设输入文件已经按时间戳顺序排列。

注意:如果data1或 的值data2可能变化,则输出行将不是唯一的并且将打印该行。这是因为uniq将整行与上一行进行比较(uniq可以跳过字段,但只能将空格识别为字段分隔符,不能使用逗号,也不能仅使用前两个字段) 。如果这就是您想要的,那么它就会按原样工作。

否则,您需要使用awkor perlor 某些东西而不是uniq检查唯一性。例如,以下用于awk仅比较前两个逗号分隔的字段(即日期和时间):

$ sed -e 's/Timestamp/Date,Hour/; s/ \(..\):[^,]*,/,\1,/' file.csv  |
    awk -F, 'prev != $1$2 {print; prev=$1$2}'

但是如果您要将sedinto的输出通过管道传输awk,您也可以awk单独使用,因为 awk 可以做所有sed可以做的事情 - 这就是 awk 的sub()gsub()gensub()函数的用途。例如

$ awk -F, -v OFS=, '{ sub(/Timestamp/,"Date,Hour");
                       $1 = gensub(/ ([0-9]+):.*/,",\\1",1,$1)
                    };
                    prev != $1$2 {print; prev=$1$2}' file.csv

或与perl

$ perl -lne 's/Timestamp/Date,Hour/;
             s/ (\d\d):.*?,/,$1,/;
             ($current) = (m/^[^,]+,\d\d|^Date),/);
             if ($prev ne $current) {print ; $prev = $current}' file.csv

相关内容