首页 > awk 如何避免文本中出现特殊符号的影响?

awk 如何避免文本中出现特殊符号的影响?

我目前分析的日志, 每行如下:

date,ip,text,source,custom-data,...
$1  ,$2,$3  ,$4    ,$5         ,...

一般情况下以,分割处理即可;

但当 text 部分有,时, 日志会在这个字段前后加上引号, 处理流程就会变成如下:

date,ip,"text A, text B",source,custom-data,...
$1  ,$2,$3     ,$4      ,$5    ,$6         ,...

这样后面的就全部乱套了, 当我想要取出$3时, 就会取得一个"text A这种东西..

所以请教一下大家, 这种情况下怎样处理比较好呢?


补充一下我目前暂时的解决方案, 使用 sed 将引号内的内容清除掉, 包括,, 从而可以正确计数.

sed 's/".*"//g' logfile

但这样的局限也是显而易见的, 内容被更改了, 结果就不够准确.


awk难以处理这样的逻辑

如果你使用GNU awk可以尝试'FPAT'

或者使用python/perl等脚本的csv模块进行格式化处理

样本

$ echo -e '1,2,"3,3,3",4,5\n6,7,8,9,0'
1,2,"3,3,3",4,5
6,7,8,9,0

pythoncsv模块处理,并以tab制表符进行域分隔,再输出

$ echo -e '1,2,"3,3,3",4,5\n6,7,8,9,0' | python -c "import csv, sys; print '\n'.join(['\t'.join(row) for row in csv.reader(sys.stdin)])"
1   2   3,3,3   4   5
6   7   8   9   0

awk以tab作为域分隔符进行处理

$ echo -e '1,2,"3,3,3",4,5\n6,7,8,9,0' | python -c "import csv, sys; print '\n'.join(['\t'.join(row) for row in csv.reader(sys.stdin)])" | awk '{print $1,$3,$5}'
1 3,3,3 5
6 8 0

当然,如果字符串中也可能有tab会造成影响的话,可以将分隔符替换成\1等不会造成冲突的非打印字符

$ echo -e '1,2,"3,3,3",4,5\n6,7,8,9,0' | python -c "import csv, sys; print '\n'.join(['\1'.join(row) for row in csv.reader(sys.stdin)])" | awk -F'\1' '{print $1,$3,$5}'
1 3,3,3 5
6 8 0

纯 awk 的解决方案,parse_csv 函数通过第一个返回一个 awk 数组,包含分隔好的 CSV 字段,直接用下标取值使用就可以了。注意,awk 的数组下标从 1 开始。

# parse csv files to an awk array.
awk -F, '{
  parse_csv(r);

  # replace following line with your code.
  print r[1], r[2], r[3], r[4];
} function parse_csv(r, _quote, _i, _n) {
  _i = 1;
  _quote = 0; # in a quoted string or not.

  for (_n = 1; _n <= NF; _n++) {
    if (_quote) {
      # quote string meets its end.
      if (substr($_n, length($_n), 1) == "\"") {
        _quote = 0;
        r[_i] = r[_i]","substr($_n, 1, length($_n) - 1);
        _i++;
      } else {
        # concat quote string with ",".
        r[_i] = r[_i]","$_n;
      }
    } else {
      # it is a quote string.
      if (substr($_n, 1, 1) == "\"") {
        _quote = 1;
        r[_i] = substr($_n, 2);
      } else {
        # copy content for normal string without quote.
        r[_i] = $_n;
        _i++;
      }
    }
  }
}'

https://gist.github.com/huandu/869fe48d6e3795875bfb

【热门文章】
【热门文章】