1

我有一个处理一些 CSV 的 bash 文件。一些输入的 CSV 格式不正确,所以我想用 sed 修复它们。引号被转义为 like\"和 not like "",所以我调用 sed 来改变它。在命令行中,这完美地工作:

sed -i 's/\\"/""/gi' input.csv

但是在 bash 脚本中,这似乎什么也没做。我想这与引号和转义序列有关,但解决方案是什么?

4

2 回答 2

5

您需要转义转义字符\才能使其正常工作:

$ echo 'bla;\"bli bli\";otherbla' | sed -e 's/\\\"/""/g'
bla;""bli bli"";otherbla

对于 bash 脚本,您需要确保从 CSV 文件中读取的行在传递给 sed 时被正确引用。您能否提供 CSV 文件的示例以及您如何从文件中读取数据?

使用cat file | while read,这是问题的一个示例:

$ cat test.csv
bla;\"bli bli\";otherbla
ble;""bli bli"";otherbla
bli;\"blo\";otherbla

$ cat test.sh
#!/bin/bash

cat test.csv | while read line;
do echo "$line" | sed -e 's/\\\"/""/g'
done

$ ./test.sh
bla;"bli bli";otherbla
ble;""bli bli"";otherbla
bli;"blo";otherbla

一种解决方案是不在脚本中使用 echo,而是直接在文件上使用 sed 并将生成的 csv 存储在新文件中:

$ sed -e 's/\\\"/""/ig' test.csv > test-tmp.csv
$ cat test-tmp.csv
bla;""bli bli"";otherbla
ble;""bli bli"";otherbla
bli;""blo"";otherbla

然后,正如评论中指出的那样,为了避免以 结尾的引用字段的破坏和错误替换\,我们可以使用 2 个 sed 表达式,并包含字段分隔符以确保我们\"替换前面或后面的字段分隔符(在我的示例中,字段分隔符是;) 但这个不考虑字段单引号,字段中的\最后一个字符,例如blo行:

$ cat test.csv
bla;\"bli bli\";otherbla
ble;""bli bli"";otherbla
bli;\"blo\";otherbla
blo;"bli bli\";otherbla
blu;""bli bli\"";otherbla

$ sed -e 's/;\\\"/;""/ig' -e 's/\\\";/"";/ig' test.csv
bla;""bli bli"";otherbla
ble;""bli bli"";otherbla
bli;""blo"";otherbla
blo;"bli bli"";otherbla
blu;""bli bli\"";otherbla

如果你有几个 sed 命令,你可以把它们放在一个脚本中,它的工作方式是一样的:

$ cat s.sed 
s/\\\"/""/g

使用它:

$ echo 'bla;\"bli bli\";otherbla' | sed -f s.sed 
bla;""bli bli"";otherbla

sed -f s.sed test.csv > test-tmp.csv
于 2012-10-05T11:48:05.643 回答
3

您是否考虑过其中一个字段合法地以 \ 字符结尾的情况?CSV 文件中的引用表示将以反斜杠结尾,后跟引号;sed 解决方案(例如您的和 Thomas 的解决方案)会破坏它。

这就是为什么 sed 是使用带引号的 csv 的错误工具的原因;有些问题只能用适当的语言(awk、Perl 或其他)递归地解决

于 2012-10-05T12:04:48.347 回答