6

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

文件:

106232145|"medicare"|"medicare,medicaid"|789

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

代码:

awk -F '|' '{print NF-1}'

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

4

5 回答 5

9
awk -F\| '{print NF}'

给出正确的结果。

于 2013-07-09T21:24:15.050 回答
5

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

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

$ head -1 /tmp/x1 | tr "|" "\012" | wc -l
4

Perl 解决方案 - 1-liner:

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

但!!!!重要的!!!

这些解决方案中的每一个 - 以及其他答案中的那些 - 都不能 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"

为了解决这个问题,应该使用适当的 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

打印正确的值

4

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

于 2013-07-09T21:35:59.720 回答
1
$ cat fieldparse.awk
#NR > 1 { print "--"; }

# Uncomment printf/print in the for loops to see
#   each field on a separate line as well as the commented line above (to show that it works).
{
    nfields = 0;
    for (i = 1; i <= NF; i++) {
        if ($i ~ /^".*[^"]$/)
            for (; i <= NF && ($i !~ /.*"$/); i++) {
                #printf("%s%s", $i, FS);
            }
        #print $i;
        nfields++;
    }
    print nfields;
    if (FILENAME == "-")
        FILENAME = "(standard input)";
    filenames[FILENAME] = sprintf("%d %d", FNR, nfields);
}

END {
    print NR, "total records processed";
    for (f in filenames) {
        split(filenames[f], fn, " ");
        printf("\t* %s: %d records with %d fields\n", f, fn[1], fn[2]);
    }
}

$ awk -F'|' -f fieldparse.awk demo.txt

它适用于任何不是双引号的单字符分隔符,这意味着标准制表符分隔、CSV 等格式(无论如何都是标准的......)

输出格式只是说明性的,最后有点装饰,但内容仍然是有用的恕我直言,例如处理多个文件。无论如何,我希望它有所帮助!:-)

编辑

这是使用 mawk 和 GNU awk (gawk) 测试的,后者在传统、POSIX 和默认模式下进行了测试。修剪注释和输出语句,发现它实际上是一个小程序,尽管它不像人们想象的那么小。

于 2013-07-10T02:45:30.090 回答
0

对于|嵌入|在此GNU awk v4.0或更高版本之间的分隔文件应该可以工作:

gawk '{ print NF }' FPAT="([^|]+)|(\"[^\"]+\")"
于 2013-07-09T21:23:39.413 回答
-1

perl -ne 'print scalar( split( /\|/, $_ ) ) . "\n"' [文件名]

于 2013-07-09T21:23:43.490 回答