我有一个 .csv 文件,其中有一些值被格式化为带有换行符或有时是项目符号的段落。
"STAT","ID","DESC"
"UPD", "1", "Updated"
"CHG", "2", "Changed"
"UPD", "3", "Updated.
Might have to update again"
"UPD", "4", "Updated.
- once
- twice
- thrice
"
"DEL", "5", "unknown"
"DEL", "6", "Deleted
Need to restore"
我需要计算记录数,使用 awk 如下,因为我知道第二列是唯一的 ID,但返回的结果比我拥有的多。上面的文本当然是假的,因为我不允许分享原件,但我尽可能地反映了实际情况。
awk '{print $2}' FS="," sample.csv | wc -l
我甚至使用 awk '{print $1}' 打印出第一列来检查第一列的值,但输出显示段落中新行的起始部分。
如果需要任何其他信息,请告诉我,我会更新问题。
答案1
一种方法awk
是
awk -v RS=$'"\n"' 'END {print NR}' sample.csv
RS=$'"\n"'
设置R记录年代eparator(默认情况下为换行符)替换为三个字符的字符串"
, newline,"
。此语法可能仅在 中有效bash
。这将导致您的文件分解为以下记录:1:
"STAT","ID","DESC
2:
UPD", "1", "Updated
3:
CHG", "2", "Changed
4:
UPD", "3", "Updated.
Might have to update again
5:
UPD", "4", "Updated.
- once
- twice
- thrice
6:
DEL", "5", "unknown
7:
DEL", "6", "Deleted
Need to restore"
这假设文件中没有尾随空格。
'END {print NR}'
读取文件直到结束,然后打印记录号 - 换句话说,记录的数量。
文本文件通常被认为是由一系列行组成,由换行符或字符序列分隔。并且,通常,文本文件中的“记录”被视为一行。但awk
允许您指定除换行符之外的记录分隔符。由于 quote-newline-quote 字符串出现在每对连续的记录在您的文件中,将其指定为记录分隔符会将文件分成(非常接近)您想要的记录。
但记录分隔符就像两个房间之间的墙——它不是任何一个房间的一部分。在正常awk
处理中,您会看到以线条形式出现的记录没有换行符 – 它们会被删除。同样,在我的回答中,引号-换行符-引号序列也会被删除。但是,由于第一条记录之前或最后一条记录之后没有记录分隔符,因此不会删除第一个和最后一个引号字符。
如果您想要逐条处理文件,此解决方案可能不够好,因为第一条记录和最后一条记录的处理方式不同。我(在某种程度上)同意 Glenn 的建议,即对于任何严肃的工作,您都应该使用“适当的 CSV 解析器”。
答案2
我强烈建议选择一种具有适当 CSV 解析器的语言。我喜欢 ruby,它非常简洁:
ruby -rcsv -e 'a = CSV.read(ARGV[0], :col_sep => ", "); puts a.length' file
7
我必须修改标题行中的列分隔符以添加空格。
答案3
以下是在 Python 中实现此目的的另一种方法:
python -c "import csv; import sys; print(sum(1 for line in csv.reader(open(sys.argv[1]))))" your-file.csv
灵感来自这个答案。