
我有一個資料集,其中包含學生的聯絡資訊,範例資料集如下
First Name, Last Name, Address, Phone Number
John, Doe, "House # 11, Street xyz, Road, Area",00000000
Sara, Taylor, "Jake Lake%, Apartment #22, Main Road, Area XYZ", 00000000
我正在運行以下命令來替換,網址列中的|將其載入到資料庫中。
awk '!(NR%2){gsub(",","|")} {printf RFS $0} {RFS="\""}' RS=\" fileName.txt > output.txt
我面臨的問題是每當我運行此命令時它都會返回以下錯誤,最初它運行正常
awk: run time error: not enough arguments passed to printf(""Jake Lake%, Apartment #22, Main Road, Area XYZ")
有什麼解決辦法嗎?我注意到%地址中出現的是這個問題嗎?
答案1
- 為了穩健性,永遠不要這樣做
printf $0
,總是使用相反,因為當您的輸入包含格式字元(如您目前所看到的)printf "%s", $0
時,前者會失敗。printf
這同樣適用於使用printf
任何輸入資料。 - 為了清晰和穩健,切勿使用全大寫的變數名稱,例如,
RFS
以避免與內建變數名稱發生衝突,並避免使程式碼看起來像是在使用內建變量,而實際上並未使用內建變數。 - 為了可讀性,請不要設定變量,例如
RS
,在腳本之後,除非您需要為不同的輸入檔案將它們設定為不同的值,在腳本之前或開始時設定變量,這樣在讀取腳本時我們會看到它們在我們之前設置看到它們被使用。 - 為了效率、簡單性、穩健性,*sub() 的第一個參數是正規表示式,而不是字串,因此請使用正規表示式 (
/.../
),而不是字串 ("..."
) 分隔符,除非您出於某些原因需要動態而不是靜態正規表示式。 - 為了清楚起見和可維護性,當您有兩個必須具有相同值的變數時,例如
RS
和RFS
,不要將它們單獨設定為相同的值,例如RS="\""; RFS="\""
,或將它們一起設定為該值,例如RS=RFS="\""
或將其中一個設定為另一個,例如RS="\""; RFS=RS
。
這是正確編寫問題中的程式碼的方法:
$ awk -v RS='"' '!(NR%2){gsub(/,/,"|")} {printf "%s%s", rfs, $0; rfs=RS}' file
First Name, Last Name, Address, Phone Number
John, Doe, "House # 11| Street xyz| Road| Area",00000000
Sara, Taylor, "Jake Lake%| Apartment #22| Main Road| Area XYZ", 00000000
若要使用 awk 對 CSV 執行更多操作,請參閱使用 awk 高效解析 csv 的最穩健方法是什麼。
答案2
RFS
您得到的錯誤是由於使用(空變數)的值和$0
作為格式字串與 的串聯printf
。
您的文件是有效的 CSV 文件,除了一些分隔逗號後面有空格(這會擾亂字段的引用Address
;引用的字段需要在分隔符後面直接包含初始引號字符)。我們可以使用csvformat
(來自 csvkit 的一部分)來修正此問題https://csvkit.readthedocs.io/en/latest/):
$ csvformat --skipinitialspace file.csv >fixed-file.csv
$ cat fixed-file.csv
First Name,Last Name,Address,Phone Number
John,Doe,"House # 11, Street xyz, Road, Area",00000000
Sara,Taylor,"Jake Lake%, Apartment #22, Main Road, Area XYZ",00000000
可以解析 CSV 的資料庫應該能夠原樣讀取它。
您是否仍想將所有嵌入的逗號替換為|
,只需將文件的分隔符號更改為逗號以外的其他內容(我將使用下面的製表符),將所有剩餘的逗號更改為管道,然後再次更改回使用逗號作為分隔符號。
我們可以直接對原始資料執行此操作:
$ csvformat --skipinitialspace --out-tabs file.csv | tr ',' '|' | csvformat --tabs >fixed-file.csv
$ cat fixed-file.csv
First Name,Last Name,Address,Phone Number
John,Doe,House # 11| Street xyz| Road| Area,00000000
Sara,Taylor,Jake Lake%| Apartment #22| Main Road| Area XYZ,00000000
使用的各種長選項的短變體是-S
for --skipinitialspace
、-T
for--out-tabs
和-t
for --tabs
。