我有一个数据集,其中包含学生的联系信息,示例数据集如下
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
。