编辑:现在我得到了答案,我标记了一个由@KamilMaciorowski 提供的更适合标题的答案,但是@oliv 的回答实际上更适合我的主要目的。(在 awk 上一致地处理带有中断的 csv 文件。)
因此,如果您在类似情况下寻找 awking,我建议您先检查一下!
请帮我准备几千个 csv 文件以供awk
处理!有些字段内部有换行符,这导致将awk
它们作为多条记录处理。但是那些有问题的换行符只发生在插入 ^M 的地方,所以我只是需要从所有文本中删除 ^M 和换行符。
*这些^M
s 确实是换行符,而不是文字插入符号和字母 M 字符串。此文件是为 .net 解析和处理而生成的,但我没有在文件生成/读取端开发应用程序,所以我真的不知道它是如何成功解析的。它专门用于具有多行字符串(注释)的某些列中的字段。
那么你如何制作这个(带有 1 个标题和 2 个记录的 csv。某些字段中有以 ^M 开头的换行符):
"header_1", "header_2", "header_3"
"1-1", "1-2", "1-3"
"2-1", "2-2_a^M
2-2_b^M
2-2_c", "2-3"
像这样吗?(csv 有 1 个标题和 2 个记录,每个记录内没有换行符。):
"header_1", "header_2", "header_3"
"1-1", "1-2", "1-3"
"2-1", "2-2_a2-2_b2-2_c", "2-3"
我尝试用它们移除,sed
但听说没有办法处理,而且我也不太明白原因。
for file in *.csv; do
sed -e "s/^M//" $file > sedded/$file;
done
无论如何,我明白了:
"header_1", "header_2", "header_3"
"1-1", "1-2", "1-3"
"2-1", "2-2_a
2-2_b
2-2_c", "2-3"
我尝试过类似的东西"s/^M\n/"
,但它并没有像我怀疑的那样起作用。我应该使用完全不同的工具吗vim
?只要它能同时处理数千个文件(每个文件包含约 500 行,我并不关心处理所需的时间),我对任何解决方案都满意。只是觉得sed
这样就行了。(如果更简单或更直接,我可以使用 DOS 命令/powershell!)
答案1
如果这些^M
-s 确实是换行符,而不是文字插入符号和字母 M 字符串,那么它们就是我们所说的\r
,CR
或者0x0d
(比较这是我的答案,它的开始)。
您的命令
sed -e "s/^M//"
不会删除\r
;它甚至不会删除文字^M
。该命令的意思是“取一行,搜索M
行首的字母(^
,看到这个),将其替换为无。
注意sed
理解\r
。仍然sed -e 's/\r//'
不是您真正需要的。它会删除,但您还\r
需要删除以下内容。您可能想尝试,这也会失败。问题是是一个文本工具,它将其视为分隔符。摘录自(重点是我的):\n
sed -e 's/\r\n//'
sed
\n
info sed
sed
通过对输入的每一行执行以下循环来操作:首先,sed
从输入流中读取一行,删除任何尾随的换行符,并将其放置在模式空间中。然后执行命令;[…]。
这意味着通常\n
不属于任何处理的字符串s/…
(或其他sed
命令)。因此,连接几行并不容易。仍然可以办到。这是您需要的命令:
sed -e ': start; /\r$/{ s/\r$//; N; s/\n// }; /\r$/b start'
解释:
: start
是一个标签。- 如果该行最后包含
\r
(即^M
字符)( ),则执行以下块:0x0d
$
{}
\r
在最后用空替换,- 从输入中附加一行(
N
), - 替换
\n
将附加行与先前的数据分开。
- 如果结果
\r
在最后包含(意味着额外的行带来了它,所以我们需要添加另一行),则跳转到start
。
答案2
假设每行有 3 个字段,并且任何值内都没有双引号,则可以使用此 GNU awk 脚本:
awk -v FPAT='"[^"]*"' '{while(NF!=3){p=$0;getline;gsub("^",p)}; p=""}1' file
FPAT
定义字段的外观,即用双引号括起来的任何内容。
awk 语句通过从文件中获取行来构建记录,直到有 3 个字段。