4

我在使用 AWK 的字段分隔符时遇到问题,输入文件如下所示

1 | 全部 | | 同义词 |
1 | 根 | | 学名 |
2 | 细菌 | 细菌 | 学名 |
2 | 莫内拉 | 莫内拉 | 部分|
2 | 原核生物 | 原核生物 | 部分|
2 | 原核生物 | 原核生物 | 部分|
2 | 原核生物 | 原核生物 | 部分|
2 | 细菌| 细菌| 爆炸名称 |

这里的字段分隔符是制表符,管道,制表符,\t|\t 所以我尝试只打印第一列和第二列

awk -F'\t|\t' '{print $1 "\t" $2}' nodes.dmp | less

而不是所需的输出,输出是第一列,后跟管道字符。我尝试转义管道\t\|\t,但输出保持不变。

1 |
1 |
2 |
2 |
2 |
2 |

打印第一列和第三列给了我最初的预期输出。

awk -F'\t|\t' '{print $1 "\t" $3}' nodes.dmp | less

但我很困惑为什么这不能按预期工作。

我知道下面的 perl one liner 可以工作,但我真正想要的是使用 awk。

perl -aln -F"\t\|\t" -e 'print $F[0],"\t",$F[1]' nodes.dmp | less
4

3 回答 3

6

The pipe | character seems to be confusing awk into thinking that \t|\t implies that the field separator could be one of \t or \t. Tell awk to interpret the | literally.

$ awk -F'\t[|]\t' '{print $1 "\t" $2}'
1   all
1   root
2   Bacteria
2   Monera
2   Procaryotae
2   Prokaryota
2   Prokaryotae
2   bacteria
于 2013-08-13T06:29:50.000 回答
1

根据您发布的输入:

  1. 您的行可以以|, not|\t和结尾
  2. 您有输入包含的案例(前两行)|\t|,并且
  3. 您的行以制表符开头

因此,tab-pipe-tab 的 FS 是错误的,因为它不会匹配上述任何情况,因为第一个只是 tab-pipe 而第二个中间的选项卡将匹配来自前面的字段,但随后只为以下字段留下管道选项卡,而第一个字段为您留下了一个不受欢迎的前导选项卡。

您实际需要的是将 FS 设置为仅制表符,然后从每个字段中剥离前导制表符:

awk -F'\t|' -v OFS='\t' '{gsub(/(^|[|])\t/,""); print $1, $2}' file

这样,您可以处理从 1 到 NF-1 的所有字段,彼此完全相同。

于 2013-08-13T11:56:41.580 回答
0

使用cut命令:

 cut -f1,2 -d'|' file.txt 

没有pipe输出:

 cut -f1,2 -d'|' file.txt | tr -d '|'
于 2013-08-13T12:04:23.003 回答