[英]Bash Scripting compliling specific csv rows
我是另一位bash腳本編寫新手(剛剛發現它,這讓我震驚!這太令人興奮了)。我想要做的是編寫一個腳本,將很多.csv文件編譯成一個bigfile.csv,刪除標題,並插入我自己的標題 我發現以下解決方案:
awk 'FNR > 1' *.csv > bigfile.csv
sed -i 1i"Ident - MD,Node ID,Date,Time,Sub Seq#,NO2..." bigfile.csv
大! 但是,當我嘗試使用此文件進行分析時,由於線條不良,我會收到錯誤消息。 我看了一下,確實有一些瘋狂的條目。
幸運的是,我要從原始.csv文件中獲得的每一行在第一列中都有條目“ MD”。 那么,有誰知道我如何告訴awk 僅采用第一個單元格中帶有“ MD”的.csv文件中的行 ?
編輯:感謝您的幫助,它起到了很大的作用! 不幸的是,那里仍然有一些奇怪的數據
CParserError: Error tokenizing data. C error: Expected 51 fields in line 6589, saw 54
通過簡單的調整,是否有辦法再次只使用51個場的線?
我將在這里展開討論,並假設您使用sed
添加的行實際上是您要剝離的標頭。
如果是這種情況,我建議您跳過sed
行,而只是告訴awk在不是第一行的文件上刪除第一行。
接下來,如果只希望在第一個字段中包含MD
文本的行,則可以使用簡單的正則表達式進行測試。
awk -F, '
FNR==1 && NR > 1 { next } # skip the header on all but the first file
NF != 51 { next } # skip this line if field count is wrong
$1 ~ /MD/ # print the line if the first field matches
' *.csv > /path/to/outputfile.csv
-F,
選項告訴awk使用逗號作為字段分隔符來拆分字段。 NR
是已處理記錄的總數,而FNR
是當前文件中的當前記錄號。 print
作為命令(打印當前行)。 當然,您可以根據需要將整個awk腳本放在一行上。 我將其拆分以便於閱讀。
如果您的outputfile.csv在獲取輸入csv文件的“全局”所在的目錄中,那么請注意,新文件將由Shell創建,而不是由awk創建,並且也可能會作為輸入文件處理。 如果您打算使用>>
將重定向重定向到現有文件,則可能會引起關注。
更新
正如您已經提到的,要添加的標頭與剝離的標頭不同,您仍然可以通過將awk腳本更改為以下內容來避免使用諸如sed之類的單獨命令:
awk -F, '
BEGIN {
print "Ident - MD,Node ID,Date,Time,Sub Seq#,NO2..."
}
FNR==1 { next } # skip the header on all files
NF != 51 { next } # skip this line if field count is wrong
$1 ~ /MD/ # print the line if the first field matches
' *.csv > /path/to/outputfile.csv
在處理任何輸入行之前,將執行awk的BEGIN
塊中的命令,因此,如果在那里打印新的標題,它們將出現在(重定向的)輸出的開頭。 (請注意,如果要在處理END
所有輸入之后生成頁腳/摘要/等,則有一個類似的END
塊。)
awk 'BEGIN{print "Ident - MD,Node ID,Date,Time,Sub Seq#,NO2..."}
if(FNR > 1){print}' *.csv > bigfile.csv
在awk處理的每個文件之后, FNR
都會重置,但是NR不會,並且NR=FNR
僅用於第一個文件。
一個小插圖 (當然還有我的測試數據)
$ cat f1
Name,Roll
A,10
B,5
5$ cat f2
Name,Roll
C,56
D,44
$ awk 'BEGIN{print "Naam,RollNo"}FNR > 1{print}' f*>final
$ cat final
Naam,RollNo
A,10
B,5
C,56
D,44
注意
如您所見,最終文件的新標頭進入了awk BEGIN
部分,該部分僅在開始時執行。
達成目標
我要從原始.csv文件中獲得的每一行的第一列均具有條目“ MD”
awk 'BEGIN{FS=",";print "Ident - MD,Node ID,Date,Time,Sub Seq#,NO2..."}
if(FNR > 1 && $1 == "MD" && NF == 51){print}' *.csv > bigfile.csv
筆記
這與第一個一般情況幾乎沒有區別。
,
作為該領域分隔符 FNR > 1 && $1 == "MD"
表示僅當第一個字段為MD($ 1 ==“ MD”)並且字段數為51(NF)時,我才不要標題(FNR = 1)並打印內容== 51) 慣用方式
正如[@ghoti]在他的評論中提到的:
awk的“默認”命令已經
{print}
因此,以上腳本可能會重寫為:
awk 'BEGIN{FS=",";print "Ident - MD,Node ID,Date,Time,Sub Seq#,NO2..."}
(FNR > 1 && NF == 51 && $1 == "MD")' *.csv > bigfile.csv
花式的一線會喜歡:-
awk -F',' 'NR > 1 && $1 ~ /^MD/ && NF == 51 { print }' *.csv > /someotherpath/bigfile.csv
使用完整的bash
腳本的正確方法將類似於以下內容:
#!/bin/bash
# Am assuming the the '.csv' files are a single ',' separated
for i in *.csv; do
[ -e "$i" ] || continue # To handle when no input *.csv files present
awk -F',' 'NR > 1 && $1 ~ /^MD/ && NF == 51 { print }' "$i" > /someotherpath/bigfile.csv
done
解決方案的關鍵是使用awk
的NR
和NF
變量,該變量跟蹤當前行和該行中的nth
字段,因此理想情況下NR > 1
將跳過標頭部分,並跳過$1 ~ /^MD/
僅返回文件中第一行以模式開頭的行,並且NF ==51
打印包含正好51個字段的行。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.