Bash awk中用于替换引号的CSV格式

Bash awk中用于替换引号的CSV格式,bash,csv,awk,Bash,Csv,Awk,我正在使用awk脚本在bash中解析csv。用“”引用的值 “1”;“2”;“3” 有时我没有在值内转义引号,例如 “1”、“2”和“2”;“3”我需要翻译成“1”;"22";“3” 如何删除$2中的这些“引号?首先,我尝试检查$2中是否有引号,但我被卡住了。如果我使用gsub,它将删除$2中的所有引号,我将得到“1”;22;“3”。我曾想过在gensub中使用gsub,但没有找到如何将函数传递到gensub的第二个参数 cat测试| awk'BEGIN{OFS=FS=“;”}\ {if($2~

我正在使用awk脚本在bash中解析csv。用“”引用的值

“1”;“2”;“3”

有时我没有在值内转义引号,例如

“1”、“2”和“2”;“3”
我需要翻译成
“1”;"22";“3”

如何删除$2中的这些“引号?首先,我尝试检查$2中是否有引号,但我被卡住了。如果我使用gsub,它将删除$2中的所有引号,我将得到
“1”;22;“3”
。我曾想过在gensub中使用gsub,但没有找到如何将函数传递到gensub的第二个参数

cat测试|
awk'BEGIN{OFS=FS=“;”}\
{if($2~/^\”*[\“].\“$/){$2=“此处需要帮助”)}\
打印}'

****************更新****************


也许还有别的办法。awk是否有特殊选项,不仅设置分隔符,而且为分隔值设置引号?如果$1等可以不被视为“值”,而是被视为引号内的值本身,那就太棒了

快速而肮脏:使用gsub并放回外部引号:

 $ echo '"1";"2"2";"3"' | awk -v q='"' 'BEGIN {FS=OFS=";"} {gsub(q,"",$2); $2 = q $2 q; print}'
"1";"22";"3"

下面的片段是一个可能的答案。
awk
语句使用
RS
而不是FS,因此每个部分类似于
“1”
“2”2“
单独打印。然后
tr
命令删除所有引号。接下来,
sed
命令在整个字段周围添加引号。最后,
paste
命令将分号加回来

echo '"1";"2"2";"3"' | awk 'BEGIN{RS=";"}{print $1}' | tr -d '"' | sed -r 's|(.*)|"\1"|' | paste -sd ";"
从所有字段中删除穿插“:

awk 'BEGIN{FS=OFS="\";\""}
     { for (i=1;i<=NF;i++) 
          gsub(/"/,"",$i); 
       printf "\"%s\"\n", $0 
     }' input.txt
您将获得:

$ awk 'BEGIN{FS=OFS="\";\""}{for (i=1;i<=NF;i++) gsub(/"/,"",$i); printf "\"%s\"\n", $0 }' input.txt
"1";"22";"3"
"1";"12345678";"12345"

这应该正确地处理转义引号以及格式错误的单引号。我假设每个字段都应该被引用

echo '"1";"2"2";"3""4"' | awk -F';' -v OFS=';' '{
    for (i=1; i<=NF; i++) {
        sub(/^"/,"",$i)
        sub(/"$/,"",$i)
        gsub(/""/,SUBSEP,$i)
        gsub(/"/,"",$i)
        gsub(SUBSEP,"\"\"",$i)
        $i = "\"" $i "\""
    }
    print
}'

注意,将在
“1”;“2;3“
data

如果您的输入可以在字段中包含
s,那么您的输入是不明确的,因为无法判断
“foo”;“bar”
是两个单独的字段还是单个字段,因此无法对其进行分析

如果您的输入不能在字段中包含
s,则不需要在字段周围加引号,您只需要:

$ awk 'BEGIN{FS="\";\""; OFS=";"} {gsub(/"/,""); $1=$1} 1' file
1;22;3
或者如果你觉得这些引语很漂亮:

$ awk 'BEGIN{FS=";"; OFS="\";\""} {gsub(/"/,""); $1="\""$1; $NF=$NF"\""} 1' file
"1";"22";"3"

当CSV文件中有多行时,这是如何工作的?我知道这个问题只显示了一行,但每个文件中有多行是合理的猜测。修复CSV生成器代码,使其不会生成格式错误的CSV数据。踢、尖叫、大叫、叫喊——在紧急情况下,为他们提供修复——但请执行som这样就没有必要修复拙劣的文件了。显然,在短期内(一次性),你必须破解数据,但你不应该这么做,任何超过一次性的都是不可接受的。如果要嵌入引号,它们应该加倍:
“1”;“2”“2”;“3”“
是有效的CSV,其中中心字段在不带引号的情况下具有值
2”2
。@JonathanLeffler谢谢,但abnf说该值是'word','word'可以包含'DQUOTE',所以我唯一能做的就是从中更改引号”但这会给我带来巨大的痛苦,因为我需要重新配置我的生产环境,这并不容易。因此,首先我需要考虑它的临时解决方案。您指的是哪种ABNF?根据任何一个有文档记录的“标准”,双引号只能在引号字段中出现两种方式:
“foo”“bar”
“foo\”bar”
。这是因为分隔符字符本身(例如数据中的
)总是可以出现在引号内(这就是为什么封装引号是必要的)因此,如果一个未转义的引号也可以出现,那么
“foo”;“bar”
表示1个字段,其中包含2个引号和分号(在标准符号中是
“foo”;“bar”
“foo\”;“bar”
)或者两个单独的字段?修复生成非标准、不明确CSV的工具,您将拥有各种选项。请注意,如果您在中引用ABNF,则(a)您的数据不是逗号分隔的,以及(b)DQUOTE有特殊处理。这很简单。唯一需要注意的是,如果输入包含格式正确的包含双引号的字段,则会丢失该信息。即,
“1”;“2”2“;“3”
是有效的CSV;第二个字段数据在不带引号时包含
2”2
,第三个字段数据包含
“3”
不带引号时,但脚本会丢失这些引号。我不认为这是一个严重的问题,但需要注意。完整处理CSV是一件棘手的事情。(您也会遇到
“4”;“5;6”;“7”
在第二个数据字段中包含分号的问题。同样,我不认为这是一个问题。)非常好的观点,@JonathanLeffler。事实上OP说“有时我没有转义引号”,这让人怀疑OP有时是否有转义引号!如果是这样,一个更强大的解决方案将是非常必要的。有趣的答案:)
echo '"1";"2"2";"3""4"' | awk -F';' -v OFS=';' '{
    for (i=1; i<=NF; i++) {
        sub(/^"/,"",$i)
        sub(/"$/,"",$i)
        gsub(/""/,SUBSEP,$i)
        gsub(/"/,"",$i)
        gsub(SUBSEP,"\"\"",$i)
        $i = "\"" $i "\""
    }
    print
}'
"1";"22";"3""4"
$ awk 'BEGIN{FS="\";\""; OFS=";"} {gsub(/"/,""); $1=$1} 1' file
1;22;3
$ awk 'BEGIN{FS=";"; OFS="\";\""} {gsub(/"/,""); $1="\""$1; $NF=$NF"\""} 1' file
"1";"22";"3"