【问题标题】:Wrap a single field with single quotes using awk使用 awk 将单个字段用单引号括起来
【发布时间】:2016-07-19 14:03:45
【问题描述】:

有许多示例使用 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 &gt; output.csv

还有……

awk -v q="'" 'BEGIN { FS="," } { sub($9, ""\'"&"\'"" );print}' container.csv > output.csv

【问题讨论】:

  • 顺便说一句,您可以在数据加载期间在字段之间使用任意分隔符。使用永远不会出现在您的数据中的分隔符(例如,ASCII 字段分隔符,如果您已确认它不存在)并且您无需担心引用。
  • 谢谢 - 下一张桌子会试一试的。

标签: regex bash csv awk sed


【解决方案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 是换行符,并且——与我们的观点相关——\' 是单引号。

【讨论】:

  • 工作正常。非常感激。谢谢!
  • 哇,这比我想象的还要糟糕!
  • 我已经澄清要显示$'' 语法,如果您知道您的shell 是bash,那么在命令行上执行此操作的方式要少得多。 :)
  • 感谢您的解释和提及$''。令人印象深刻的东西:)
  • @EdMorton,...啊,你说得对;我的脑海里有-F 两者都设置了。
【解决方案2】:

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

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

【讨论】:

  • 感谢您的帮助,但 awk 不喜欢它:awk '{ $9 = '"'"'$9'"'"' }' container.csv &gt; test.csv awk: cmd. line:1: { $9 = '$9' } awk: cmd. line:1: ^ invalid char ''' in expression awk: cmd. line:1: { $9 = '$9' } awk: cmd. line:1: ^ syntax error
  • @Stelios,是的,我弄错了,因此进行了编辑。我建议使用脚本,您可以在我的答案的当前版本中看到。
【解决方案3】:

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

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

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

【讨论】:

  • 可能想清楚这是一个 awk 主义——在单引号内,shell 不会解释——但这绝对是解决 OP 问题的好方法。
【解决方案4】:

使用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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-03-02
    • 1970-01-01
    • 2014-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多