计算管道分隔文件中的列数

Mau*_*zey 4 linux shell perl awk

我有一个管道|分隔文件.

文件:

106232145|"medicare"|"medicare,medicaid"|789
Run Code Online (Sandbox Code Playgroud)

我想计算每行中的字段数.我尝试了下面的代码

码:

awk -F '|' '{print NF-1}'
Run Code Online (Sandbox Code Playgroud)

这将结果返回为5而不是4.这是因为awk将"medicare | medicaid"作为两个不同的字段而不是一个字段

unx*_*nut 7

awk -F\| '{print NF}'
Run Code Online (Sandbox Code Playgroud)

给出正确的结果.


DVK*_*DVK 5

纯 Unix 解决方案(没有 awk/Perl):

$ cat  /tmp/x1
1|2|3|34
4534|23442|1121|334434

$ head -1 /tmp/x1 | tr "|" "\012" | wc -l
4
Run Code Online (Sandbox Code Playgroud)

Perl 解决方案 - 1-liner:

$ perl5.8 -naF'\|' -e 'print scalar(@F)."\n";exit;' /tmp/x1
4
Run Code Online (Sandbox Code Playgroud)

但!!!!重要的!!!

这些解决方案中的每一个 - 以及其他答案中的那些 - 都不能 100% 工作!

也就是说,当它是一个真正的“管道分隔”文件时它们都会中断,管道是字段中的有效字符(并且该字段被引用),真正的 CSV 文件的工作方式。

例如

$ cat /tmp/x2
"0|1"|2|3|34
4534|23442|1121|334434
$ perl5.8 -naF'\|' -e 'print scalar(@F)."\n";exit;' /tmp/x1
5   <----- BROKEN!!! There are only 4 fields, first field is "0|1"
Run Code Online (Sandbox Code Playgroud)

要解决这个问题,应该使用适当的 CSV(或分隔文件)解析器,例如 Perl 中的解析器

$ perl5.8 -MText::CSV_XS 
-ne '$csv=Text::CSV_XS->new({sep_char => "|"});  $csv->parse($_); 
print $csv->fields(); print "\n"; exit;' /tmp/x2
Run Code Online (Sandbox Code Playgroud)

打印正确的值

4
Run Code Online (Sandbox Code Playgroud)

请注意,简单地使用复杂的 RegEx修复awkorsed解决方案并不容易,因为在包含管道和引用的 PSV 字段之上,规范还允许将引号作为字段的一部分。这不适合一个很好的 RegEx 解决方案。

  • `tr`、`head` 和 `wc` 并不比 `awk` 更“纯粹的 unix”...... `perl` 是一个稍微不同的故事...... (2认同)