根據時間戳列合併並附加日期和時間列

根據時間戳列合併並附加日期和時間列

我有一個 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

相關內容