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



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

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

如果我取FS="|",则脚本将上述字段作为四个字段,而这实际上是三个字段。如果取FS=""|"",则有两个问题:

  1. 我必须分别处理第一个和最后一个字段,"Boolean123"
  2. 更重要的是,现在因为我们不再有双引号了,当我取每个字段和处理时,一些函数或命令可能不会取字段中存在的整个字符串(因为它们可能被空格和不同的其他字符分隔)。第二个字段变成dada -sdf|xcvnb,即没有引号,这对于某些命令可能会给出错误的结果,因为-可能被解释为选项,或者只有第一个单词可以作为参数,空格后的字符串其余部分根本不考虑。

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

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

对于gawk,您可以使用FPAT变量来定义字段的样式。在您的示例中,字段由"后跟0个或多个任意字符("和最后的"除外)组成。

有了这个,你可以简单地打印第一个字段$1和最后一个字段$NF:
gawk '{print $1,$NF}' FPAT='"[^"]*"' OFS="|" 
    <<< '"Boolean"|"dada -sdf|xcvnb"|"123"'
输出:

"Boolean"|"123"

我将使用真正的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"

我想告诉gawk,只有当它后面跟一个"并且前面有一个"

"时,才把FS作为|

你可以在perl中做到这一点,正面向前看和向后看…

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


进一步阅读:

  • Perl标志-pe, -pi, -p, -w, -d, -i, -t?
  • perl命令开关

最新更新