我有一個 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
sort
並uniq
可以為您提供問題中顯示的輸出範例。
$ 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
可以跳過字段,但只能將空格識別為字段分隔符,不能使用逗號,也不能僅使用前兩個字段) 。如果這就是您想要的,那麼它就會按原樣工作。
否則,您需要使用awk
or perl
or 某些東西而不是uniq
檢查唯一性。例如,以下用於awk
僅比較前兩個逗號分隔的欄位(即日期和時間):
$ sed -e 's/Timestamp/Date,Hour/; s/ \(..\):[^,]*,/,\1,/' file.csv |
awk -F, 'prev != $1$2 {print; prev=$1$2}'
但是如果您要將sed
into的輸出通過管道傳輸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