use*_*009 0 sed awk text-processing
我有一个包含两个字段的大文件,第一个字段表示对象名称,第二个字段表示该对象的大小:
A 1
A 2
B 4
ABC 12
C 5
A 9
B 3
ABC 6
Run Code Online (Sandbox Code Playgroud)
我想用以下格式总结列表:
A 1,2,9
ABC 12,6
B 4,3
C 5
Run Code Online (Sandbox Code Playgroud)
我想出的解决方案是创建文件中存在的对象的唯一列表,遍历它并将其与原始文件匹配
for object in $(awk '{print $1}' objects_with_sizes.txt | sort -u);do
echo -n "$object "
awk -v pattern="$object" '$1==pattern{printf "%s%s" ,sep,$2;sep=","} END{print ""}' objects_with_sizes.txt
done
Run Code Online (Sandbox Code Playgroud)
此实现需要很长时间才能运行,是否有更有效的方法来创建所需的输出?
$ awk '{ object[$1]= (object[$1]==""?"":object[$1] ",") $2 }
END { for(obj in object) print obj, object[obj] }' infile
A 1,2,9
B 4,3
C 5
ABC 12,6
Run Code Online (Sandbox Code Playgroud)
效率更高一点(内存的使用;对于无法放入内存的大文件很重要),即不将文件部分缓冲到内存中,而 awk 命令单独执行上述操作,但仅在对象键更改之前:
$ <infile sort -k1,1 -k2,2n |\
awk 'pre!=$1 { if(obj) { print obj; obj="" } }
{ obj= (obj==""?$1 " ":obj ",") $2; pre=$1 }
END{ if(obj) print obj }'
A 1,2,9
ABC 6,12
B 3,4
C 5
Run Code Online (Sandbox Code Playgroud)
使用 GNU datamash
:
$ datamash -t ' ' -s -g 1 collapse 2 <file
A 1,2,9
ABC 12,6
B 4,3
C 5
Run Code Online (Sandbox Code Playgroud)
选项:
-t '_'
使用空格字符作为字段分隔符-s
在分组之前对输入进行排序-g 1
在第一个字段上分组collapse 2
将第二个字段的值折叠为逗号分隔的列表