我有一个管道|
分隔文件。
文件:
106232145|"medicare"|"medicare,medicaid"|789
我想计算每行中的字段数。我尝试了下面的代码
代码:
awk -F '|' '{print NF-1}'
这将结果返回为5而不是4.这是因为awk将“medicare | medicaid”视为两个不同的字段而不是一个字段
答案 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修复awk
或sed
解决方案将无法轻松实现,因为在包含管道且引用的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"'
的 [文件名] 的