簡體   English   中英

Bash腳本編譯特定的csv行

[英]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

解決方案的關鍵是使用awkNRNF變量,該變量跟蹤當前行和該行中的nth字段,因此理想情況下NR > 1將跳過標頭部分,並跳過$1 ~ /^MD/僅返回文件中第一行以模式開頭的行,並且NF ==51打印包含正好51個字段的行。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM