sort | uniq | xargs grep ... 当行包含空格

4
我有一个逗号分隔的文件"myfile.csv",其中第5列是日期/时间戳。(mm/dd/yyyy hh:mm)。我需要列出所有包含重复日期的行(有很多)。
我正在使用通过Cygwin为WinXP的bash shell。
$ cut -d, -f 5 myfile.csv | sort | uniq -d 

正确返回重复日期列表

01/01/2005 00:22
01/01/2005 00:37
[snip]    
02/29/2009 23:54

但是我不知道如何将这个内容传递给grep以获取所有行。显然,我不能直接使用xargs,因为输出包含空格。我认为可以使用uniq -z -d,但由于某种原因,组合这些标志会导致uniq返回空值。

因此,鉴于这一点:

 $ cut -d, -f 5 myfile.csv | sort | uniq -d -z | xargs -0 -I {} grep '{}' myfile.csv

无法工作...我该怎么办?

我知道我可以使用perl或其他脚本语言来完成这个任务...但是我的固执天性坚持认为我应该能够使用标准命令行工具如sortuniqfindgrepcut等在bash中完成它。

请教各位bash大师,我该如何使用典型的cli工具获取所需的行列表?

5个回答

10
  1. sort -k5,5将根据字段进行排序并避免使用cut命令;
  2. uniq -f 4将忽略uniq的前四个字段;
  3. 在uniq后加上-D将得到所有重复的行(相对于-d只得到一个);
  4. 但是,uniq将期望制表符分隔而不是csv,因此使用tr '\t' ','来修复它。

问题是如果您有#5之后不同的字段。您的日期长度都相同吗?您可能可以添加-w 16(包括时间)或-w 10(仅限日期)来进行uniq操作。

tr '\t' ',' < myfile.csv | sort -k5,5 | uniq -f 4 -D -w 16

如果CSV格式很重要,那么在末尾加上"Yes +1."和"tr '\t' ','"。 - kmkaplan

2
uniq-z 选项需要输入以 NUL 分隔。您可以通过以下方式过滤 cut 的输出:
tr '\n' '\000'

为了获取零分隔的行。然后使用sortuniqxargs处理选项。尝试像这样做:
cut -d, -f 5 myfile.csv | tr '\n' '\000' | sort -z | uniq -d -z | xargs -0 -I {} grep '{}' myfile.csv

编辑:管道中tr的位置错误。


--- 正是我所寻找的。 - Felipe Alvarez

1

您可以使用 -d 选项告诉 xargs 将每行作为一个完整的参数使用。尝试:

cut -d, -f 5 myfile.csv | sort | uniq -d | xargs -d '\n' -I '{}' grep '{}' myfile.csv

1

尝试使用sed转义空格:

echo 01/01/2005 00:37 | sed 's/ /\\ /g'
cut -d, -f 5 myfile.csv | sort | uniq -d | sed 's/ /\\ /g' | xargs -I '{}' grep '{}' myfile.csv

(另一种方法是将重复的日期行读入IFS=$'\n'数组中,并在for循环中迭代它。)

更正:sed表达式中应该有两个反斜杠echo 01/01/2005 00:37 | sed 's/ /\\ /g' - phil

1

这是 awk 的一个很好的候选项:

BEGIN { FS="," }
{ split($5,A," "); date[A[0]] = date[A[0]] " " NR }
END { for (i in date) print i ":" date[i] }
  1. 将字段分隔符设置为逗号(CSV)。
  2. 在空格上拆分第五个字段,将结果粘贴到A中。
  3. 将行号连接到我们已经存储的该日期的列表中。
  4. 打印出每个日期的行号。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接