使用awk用单引号包装单个字段

问题描述 投票:1回答:4

有许多使用awk用双引号包装字段的例子。我没有成功地尝试在postgresql中用数字加载csv文件的单引号括起一个字段。

以下是我的一些尝试:

#!/usr/bin/awk -f
BEGIN { FS=OFS=","}

{
  for (i = 1; i <= NF; ++i)
    if($i == 9)
    {
        $i = "\'' $i \''"
    }

  print $0 >> "output.csv"
}

要么

awk 'BEGIN { OFS=FS="," } { $9= ""'" $9 ""'"} 1' container.csv > output.csv

也...

awk -v q="'" 'BEGIN { FS="," } { sub($9, ""\'"&"\'"" );print}' container.csv > output.csv
regex bash csv awk sed
4个回答
1
投票
$ awk 'BEGIN { FS = OFS = "," } { $9= "'"'"'" $9 "'"'"'"; print }' \
>    <<<one,two,three,four,five,six,seven,eight,nine,ten
one,two,three,four,five,six,seven,eight,'nine',ten

这里的棘手问题是通过bash将你的引号引入awk - 如果你在单引号命令行参数中有一个引号,那么它将被视为结束从'BEGIN开始的引用上下文,而不是作为要发送的文字内容到awk

因此,"'"'"'"做了必要的诡计:

  • 第一个字符"是字面意思,传递给awk
  • 第二个字符'是语法,用于告诉shell结束从命令行前面开始的引号
  • 第三个字符"是语法,用于开始一个新的(双引号)引用上下文。
  • 第四个字符'在该上下文中是字面的。
  • 第五个字符"结束了从第三个字符开始的双引号上下文
  • 第六个字符'是语法,恢复以字符2结尾的单引号上下文
  • 第七个字符"是字面意思,传递给awk。

因此,实际传递给awk以用作上述脚本的是:

BEGIN { FS = OFS = "," } { $9= "'" $9 "'"; print }

...如果你愿意,你可以直接把它放在一个文件中;如果那个awk脚本有一个#!/usr/bin/awk -f shebang,它应该在直接作为命令执行时起作用。


顺便说一句,如果你的shell是bash,那么有一个替代的引用上下文会使这个更糟糕:

$ awk $'BEGIN { FS = OFS = "," } { $9= "\'" $9 "\'"; print }'

$''内部,反斜杠逃脱被尊重 - \t是一个标签,\f是字段分隔符,\r是换行符,并且 - 与我们的点相关 - \'是单引号。


1
投票

这在脚本中更容易,因为您不需要担心封闭的引号:

BEGIN { FS = OFS = "," }

{ 
    $9 = "'" $9 "'"
    print
}

我不确定你的循环应该做什么!

使用Charles提供的输入进行测试:

$ cat file
one,two,three,four,five,six,seven,eight,nine,ten
$ awk -f script.awk file
one,two,three,four,five,six,seven,eight,'nine',ten

1
投票

只需在需要单引号的地方使用八进制转义序列\047

awk 'BEGIN{FS=OFS=","} { $9= "\047" $9 "\047"; print }'

这避免了引用的任何复杂性以及其他方法带来的任何意外。


1
投票

使用sed的解决方案

$ s='one,two,three,four,five,six,seven,eight,nine,ten'

$ # s///n means nth matching occurrence
$ echo "$s" | sed "s/[^,]*/'&'/9"
one,two,three,four,five,six,seven,eight,'nine',ten
$ # * used as quantifier so that it will work on empty fields too
$ echo 'a,c,,d' | sed "s/[^,]*/'&'/3"
a,c,'',d  

$ # or if hex escape sequences are allowed
$ # this is preferred as it avoids shell interpretation within double quotes
$ echo "$s" | sed 's/[^,]*/\x27&\x27/9'
one,two,three,four,five,six,seven,eight,'nine',ten
© www.soinside.com 2019 - 2024. All rights reserved.