"grep" 包含多行字段的 csv 文件?

"grep" a csv file including multi-lines fields?

file.csv:

XA90;"standard"
XA100;"this is
the multi-line"
XA110;"other standard"

我想像这样 grep "XA100" 条目:

grep XA100 file.csv

得到这个结果:

XA100;"this is
the multi-line"

但是 grep return 只有一行:

XA100;"this is

source.csv 包含 3 个条目。 "XA100" 条目包含多行字段。 而且 grep 似乎不是 "grep" 包含多行字段的 CSV 文件的正确工具。

你知道做这份工作的方法吗?

编辑:现实世界文件包含许多列。研究的术语可以在任何列中(不在行的开头,也不在字段的开头)。所有字段都用"封装。任何字段都可以包含多行,从1行到任意行,这是无法预测的。

试试这一行:

awk '/^XA100;/{p=1}p;p&&/"$/{p=0}' file

我稍微扩展了你的例子:

kent$  cat f
XA90;"standard"
XA100;"this is
the
multi-
line"
XA110;"other standard"

kent$  awk '/^XA100;/{p=1}p;p&&/"$/{p=0}' f
XA100;"this is
the
multi-
line"

在您提到的评论中:在真实世界的文件中,每一行都以“ 开头。我假设它们也以 " 结尾并向您展示:

测试文件:

$ cat file
"single line"
"multi-
lined"

代码和输出:

$ awk 'BEGIN{RS=ORS="\"\n"} /single/' file
"single line"
$ awk 'BEGIN{RS=ORS="\"\n"} /m/' file
"multi-
lined"

您还可以参数化搜索:

$ awk -v s="multi" 'BEGIN{RS=ORS="\"\n"} match([=12=],s)' file
"multi-
lined"

尝试: 解决方案一:

awk -v RS="XA" 'NR==3{gsub(/$\n$/,"");print RS [=10=]}'  Input_file

将记录分隔符设为字符串 XA 然后在此处查找第 3 行,然后将 $\n$(即删除行尾的额外行)全局替换为 NULL。然后用当前行打印记录分隔符。

方案二:

awk '/XA100/{print;getline;while([=11=] !~ /^XA/){print;getline}}'  Input_file

寻找字符串 XA100 然后打印当前行并使用 getline 转到下一行,然后使用 while 循环 运行 并打印这些行直到一行从 XA 开始。

如果此文件是从 MS-Excel 或类似文件导出的,则行以 \r\n 结尾,而引号内的换行符只是 \n,所以您只需要:

$ awk -v RS='\r\n' '/XA100/' file
XA100;"this is
the multi-line"

以上使用 GNU awk 进行多字符 RS。在某些平台上,例如cygwin,你必须添加 -v BINMODE=3 以便 gawk 看到 \rs 而不是它们被底层 C 基元剥离。

否则,如果没有真正的 CSV 解析器(awk 目前没有但正在为 GNU awk 工作),通常很难解析 CSV 文件,但您可以这样做(再次使用 GNU awk for multi -char RS):

$ cat file
XA90;"standard"
XA100;"this is
the multi-line"
XA110;"other standard"

$ awk -v RS="\"[^\"]*\"" -v ORS= '{gsub(/\n/," ",RT); print [=11=] RT}' file
XA90;"standard"
XA100;"this is the multi-line"
XA110;"other standard"

用空白字符替换引号内的所有换行符,然后将其作为常规的每条记录 1 行文件进行处理。

使用 PS 响应,这适用于小示例:

sed 's/^X/\n&/' file.csv | awk -v RS= '/XA100/ {print}'

对于我真实世界的 CSV 文件,有很多列,在任何地方都有研究术语,多行数未知,字符“替换为”,多行行以“”开头,所有字段都被封装通过“,这有效。注意在 sed 部分排除第二个字符”:

sed 's/^"[^"]/\n&/' file.csv | awk -v RS= '/RESEARCH_TERM/ {print}'

因为任何条目的第一列都不能以“”开头。第一列总是看起来像 "XXXXXXXXX",其中 X 是任何字符,但 ".

感谢大家的这么多回复,也许其他解决方案也有效,具体取决于您使用的 CSV 文件格式。