如何添加 if-else 条件来定义 gawk、ksh 中的字段分隔符?

How can I add if-else condition to define the field separator in gawk, ksh?

我必须处理管道分隔文件中的一些数据,其中每个字段都用双引号引起来。

"Boolean"|"dada -sdf|xcvnb"|"123"

如果我取FS="|",那么脚本将上面的作为四个字段,而实际上是三个字段。如果我选择 FS="\"|\"" 那么我有两个问题:

  1. 我必须分别处理第一个和最后一个字段 "Boolean123"
  2. 更重要的是,由于我们不再使用双引号,当我获取每个字段和过程时,某些函数或命令可能不会获取字段中的整个字符串(因为它们可能被分开通过 spaces 和不同的其他字符)。例如第二个字段变为 dada -sdf|xcvnb 即没有引号,对于某些命令可能会给出错误的结果,因为 - 可能被解释为选项,或者只有第一个单词可能被视为参数和 [ 之后的字符串的其余部分=34=]根本没有考虑。

我的想法 - 我想告诉 gawk 只有当它后面跟着一个 " 并且前面有一个 " 时才把 FS 当作 |。这样我就不会去掉字段中的双引号。

如何编写代码?有办法吗?

使用 gawk,您可以使用 FPAT 变量来定义字段的外观模式。在您的情况下,字段由 " 后跟零个或多个任意字符组成, " 和最后一个 ".

有了这个你可以简单地打印第一个字段 </code> 和最后一个字段 <code>$NF:

gawk '{print ,$NF}' FPAT='"[^"]*"' OFS="|" \
    <<< '"Boolean"|"dada -sdf|xcvnb"|"123"'

输出:

"Boolean"|"123"

I want to tell gawk that take FS as | only if it is followed by a " and preceded by a "

您可以在 perl 中通过积极的前瞻和后视来做到这一点...

$ perl -F'/"\K\|(?=")/' -le 'print "$F[0] : $F[1] : $F[2]"' ip.txt 
"Boolean" : "dada -sdf|xcvnb" : "123"
  • -F 指定字段分隔符并保存在@F数组中
    • 还设置了 -n 标志,这意味着在循环中迭代输入文件,默认情况下不打印行
    • 要按空格拆分,可以简单地使用 -a 选项
  • '/"\K\|(?=")/' 使用正则表达式指定字段分隔符。 "\K 是积极的后视,(?=") 是积极的前瞻。 \|为分隔符(|需要转义)
  • -l 从输入行中去除换行符并将换行符添加到 print 语句
  • -e 允许直接传递 perl 代码而不是从文件
  • $F[0]数组索引以0开头,这个指的是@F数组的第一个元素


进一步阅读:

我会使用真正的 CSV 解析器。我喜欢 ruby 的:

ruby -rcsv -e '
  opts = { :col_sep => "|", :force_quotes => true }
  CSV.parse(STDIN.read, opts) do |row|
    row.delete_at(1)
    puts row.to_csv(opts)
  end
' filename

产出

"Boolean"|"123"