Bash 如果只有非空字段用双引号括起来,如何读取CSV文件?
我正在尝试读取Bash脚本中的CSV文件。我成功地使用了Bash 如果只有非空字段用双引号括起来,如何读取CSV文件?,bash,csv,unix,awk,Bash,Csv,Unix,Awk,我正在尝试读取Bash脚本中的CSV文件。我成功地使用了gawk并指定FPAT如下: gawk -v LOGFILE="${LOGFILE}" 'BEGIN { FPAT = "([^,]+)|(\"[^\"]+\")" } NR == 1{ # doing some logic with header } NR >= 2{ # doing some logic with fields }' <filename> 现在,对于这些数据,我得到了错
gawk
并指定FPAT
如下:
gawk -v LOGFILE="${LOGFILE}" 'BEGIN {
FPAT = "([^,]+)|(\"[^\"]+\")"
}
NR == 1{
# doing some logic with header
}
NR >= 2{
# doing some logic with fields
}' <filename>
现在,对于这些数据,我得到了错误的数据,因为它忽略了逗号,这给了我错误的提取数据的位置号。
例如,它告诉我们“7865431234”位于第3位,而它位于第6位
有人可以建议更改以获得字段的正确位置吗?您的
FPAT
要求每个字段至少包含一个字符,但您希望识别零字符的空字段。添加一个允许零字符的FPAT
替代方案:
gawk 'BEGIN { FPAT = "([^,]+)|(\"[^\"]+\")|" }
{ printf "%d:%d:", NR, NF; for (i = 1; i <= NF; i++) printf("[%s]", $i); print "" }'
这非常清楚地显示了四个空字段
现在,您所要做的就是处理:
"Mr ""Manipulator"", the Artisan","29th Street, Delhi, India",,,"",,,"INVALID"
其中引用的值内有双引号。这并不难管理:
gawk 'BEGIN { FPAT = "([^,]+)|(\"([^\"]|\"\")*\")[^,]*|" }
{ printf "%d:%d:", NR, NF; for (i = 1; i <= NF; i++) printf("%d[%s]", i, $i); print "" }' "$@"
这将产生:
1:8:1["RAM"]2["31st street, Bengaluru, India"]3[]4[]5[]6["7865431234"]7[]8["VALID"]
2:8:1["Mr ""Manipulator"", the Artisan"]2["29th Street, Delhi, India"]3[]4[]5[]6[]7[]8["INVALID"]
3:7:1["Some"]2[""]3["Empty"]4[""]5[Fields "" Wrapped]6[""]7[in quotes]
4:6:1["Malformed" CSV]2[Data]3["Note it has data after" a close quote]4["and before a comma,"]5[]6["INVALID"]
请注意,字段编号是作为括号中数据的前缀包含的(因此我稍微调整了打印格式)
关于唯一不处理的格式是可以在字段的数据中嵌入换行符的格式-根据基于行的输入的性质,它假设没有字段被拆分为多行。(这也意味着它无法正确识别以双引号开头且在行尾之前没有匹配双引号的字段。我想您可以添加一个替代项来识别该字段。最好只是正确地处理数据。)
请注意中的建议,即使用设计用于处理CSV的工具来处理CSV。这通常是一个好主意,而且你必须处理的变量集越复杂,这个主意就越好。这是一个复杂的正则表达式,您应该考虑使用。还要注意的是,尽管正式且严格地定义了CSV的一个版本,但有多个程序(包括MS Office)处理不同但相关的格式。如果您有需要解析的CSV,那么尽管您通常可以使用正则表达式对其进行解析,但使用解析器要容易得多 大概是这样的:
#!/usr/bin/env perl
use strict;
use warnings;
use Text::CSV;
my $csv = Text::CSV -> new;
open ( my $input, '<', 'flarg.csv' ) or die $!;
while ( my $row = $csv -> getline ( $input ) ) {
if ( $. == 1 ) {
# do first row stuff;
print "Header: ", join ",", @$row,"\n";
}
else {
print join "\n", @$row;
}
}
值本身是否可以包含逗号?是的,因为第二个字段是地址。它可以包含任意数量的逗号。我会在模块中使用perl。我对perl不太熟悉。使用bash脚本有什么方法可以实现吗?@javabash-spring:您使用的是
gawk
,而不是bash
。
"RAM","31st street, Bengaluru, India",,,,"7865431234",,"VALID"
"Mr ""Manipulator"", the Artisan","29th Street, Delhi, India",,,,,,"INVALID"
"Some","","Empty","",Fields "" Wrapped,"",in quotes
"Malformed" CSV,Data,"Note it has data after" a close quote,"and before a comma,",,"INVALID"
1:8:1["RAM"]2["31st street, Bengaluru, India"]3[]4[]5[]6["7865431234"]7[]8["VALID"]
2:8:1["Mr ""Manipulator"", the Artisan"]2["29th Street, Delhi, India"]3[]4[]5[]6[]7[]8["INVALID"]
3:7:1["Some"]2[""]3["Empty"]4[""]5[Fields "" Wrapped]6[""]7[in quotes]
4:6:1["Malformed" CSV]2[Data]3["Note it has data after" a close quote]4["and before a comma,"]5[]6["INVALID"]
#!/usr/bin/env perl
use strict;
use warnings;
use Text::CSV;
my $csv = Text::CSV -> new;
open ( my $input, '<', 'flarg.csv' ) or die $!;
while ( my $row = $csv -> getline ( $input ) ) {
if ( $. == 1 ) {
# do first row stuff;
print "Header: ", join ",", @$row,"\n";
}
else {
print join "\n", @$row;
}
}
#!/usr/bin/env perl
use strict;
use warnings;
use Text::ParseWords;
while ( my $line = <DATA> ) {
my @fields = parse_line(',', 1, $line);
print join "\n", @fields;
}
__DATA__
"RAM","31st street, Bengaluru, India",,,,"7865431234",,"VALID"