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

时间:2013-07-09 21:21:08

标签: linux perl shell awk

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

文件:

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

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

代码:

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

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

5 个答案:

答案 0 :(得分:7)

awk -F\| '{print NF}'

给出正确的结果。

答案 1 :(得分:4)

纯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衬里:

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

<强> BUT !!!!重要!!!

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

即,它们都是真正的“管道分离”文件,管道是字段中的有效字符(以及引用的字段),真正的CSV文件的工作方式

E.g。

$ 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修复awksed解决方案将无法轻松实现,因为在包含管道且引用的PSV字段之上,规范也允许引用作为该字段的一部分。这不适合一个很好的RegEx解决方案。

答案 2 :(得分: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和默认模式下进行了测试。修剪注释和输出语句,发现它实际上是一个小程序,虽然它不像人们想的那么小。

答案 3 :(得分:0)

对于在|或更高版本之间嵌入|的{​​{1}}分隔文件应该有效:

GNU awk v4.0

答案 4 :(得分:-1)

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