"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 看到 \r
s 而不是它们被底层 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 文件格式。
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 看到 \r
s 而不是它们被底层 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 文件格式。