Unix,对 file.csv 中的行进行分组并对列求和
Unix, group rows and sum values of columns from file.csv
我有这个file.csv
"201707"|"51976551"|1|0|1|"20170702"
"201707"|"51955194"|1|0|0|"20170702"
"201707"|"51923555"|1|0|1|"20170702"
"201707"|"51976551"|1|0|1|"20170703"
"201707"|"51955194"|1|0|0|"20170703"
"201707"|"51923555"|1|0|1|"20170703"
"201707"|"51960597"|1|0|0|"20170703"
我希望结果是按数字分组并对第 3、4 和 5 列求和
"201707"|"51976551"|2|0|2
"201707"|"51955194"|2|0|0
"201707"|"51923555"|2|0|2
"201707"|"51960597"|1|0|0
我试过:
cat file.csv | awk -F"|" '
{ a[] += }
END {
for (i in a) {
printf "%s|%s\n", i, a[i];
}
}
'
结果是:
"51976551"|2
"51955194"|2
"51923555"|2
"51960597"|1
只显示第三列的总和,但我还需要2列。
这种情况我该怎么办?
尝试:
$ awk -F"|" '{ a[ OFS ]+=; b[ OFS ]+=; c[ OFS ]+= }
END {
for (i in a) {
print i, a[i], b[i], c[i];
}
}
' OFS=\| file.csv
"201707"|"51976551"|2|0|2
"201707"|"51960597"|1|0|0
"201707"|"51923555"|2|0|2
"201707"|"51955194"|2|0|0
工作原理
-F"|"
这会将输入的字段分隔符设置为 |
。
a[ OFS ]+=; b[ OFS ]+=; c[ OFS ]+=
这会跟踪第三、第四和第五列的总数。
END {
for (i in a) {
print i, a[i], b[i], c[i];
}
}
这会打印出结果。
OFS=\|
这告诉 awk 使用 |
作为输出的字段分隔符。
要保留顺序:
在END块中处理
awk 'BEGIN{
FS=OFS="|"
}
{
k = OFS ;
if(!(k in t)){
o[++c]=k;
t[k]
}
for(i=3; i<=5; i++)
a[k OFS i]+=$i
}
END{
for(i=1; i in o; i++)
{
printf "%s", o[i];
for(j=3; j<=5; j++)
printf "%s%s", OFS, a[o[i] OFS j];
print ""
}
}
' infile
或者通过读取同一个文件两次 (GNU awk)
awk 'BEGIN{
FS=OFS="|"
}
function ps(f)
{
for(i=3;i<=5;i++)
if(f)
{
a[k OFS i]+=$i;
t[k]
}else
s=(s ? s OFS :"") a[k OFS i]
}
{
k= OFS
}
FNR==NR{
ps(1);
next
}
k in t{
s="";
ps();
print k, s;
delete t[k]
}
' infile infile
输入:
$ cat input
"201707"|"51976551"|1|0|1|"20170702"
"201707"|"51955194"|1|0|0|"20170702"
"201707"|"51923555"|1|0|1|"20170702"
"201707"|"51976551"|1|0|1|"20170703"
"201707"|"51955194"|1|0|0|"20170703"
"201707"|"51923555"|1|0|1|"20170703"
"201707"|"51960597"|1|0|0|"20170703"
输出-1:
$ awk 'BEGIN{FS=OFS="|"}{k = OFS ; if(!(k in t)){o[++c]=k; t[k]} for(i=3; i<=5; i++)a[k OFS i]+=$i}END{for(i=1; i in o; i++){printf "%s", o[i]; for(j=3; j<=5; j++)printf "%s%s", OFS, a[o[i] OFS j]; print ""}}' infile
"201707"|"51976551"|2|0|2
"201707"|"51955194"|2|0|0
"201707"|"51923555"|2|0|2
"201707"|"51960597"|1|0|0
输出 2:
$ awk 'BEGIN{FS=OFS="|"}function ps(f){for(i=3;i<=5;i++)if(f){ a[k OFS i]+=$i; t[k] }else s=(s ? s OFS :"") a[k OFS i]}{k= OFS }FNR==NR{ps(1); next}k in t{s=""; ps(); print k, s; delete t[k] }' infile infile
"201707"|"51976551"|2|0|2
"201707"|"51955194"|2|0|0
"201707"|"51923555"|2|0|2
"201707"|"51960597"|1|0|0
我有这个file.csv
"201707"|"51976551"|1|0|1|"20170702"
"201707"|"51955194"|1|0|0|"20170702"
"201707"|"51923555"|1|0|1|"20170702"
"201707"|"51976551"|1|0|1|"20170703"
"201707"|"51955194"|1|0|0|"20170703"
"201707"|"51923555"|1|0|1|"20170703"
"201707"|"51960597"|1|0|0|"20170703"
我希望结果是按数字分组并对第 3、4 和 5 列求和
"201707"|"51976551"|2|0|2
"201707"|"51955194"|2|0|0
"201707"|"51923555"|2|0|2
"201707"|"51960597"|1|0|0
我试过:
cat file.csv | awk -F"|" '
{ a[] += }
END {
for (i in a) {
printf "%s|%s\n", i, a[i];
}
}
'
结果是:
"51976551"|2
"51955194"|2
"51923555"|2
"51960597"|1
只显示第三列的总和,但我还需要2列。 这种情况我该怎么办?
尝试:
$ awk -F"|" '{ a[ OFS ]+=; b[ OFS ]+=; c[ OFS ]+= }
END {
for (i in a) {
print i, a[i], b[i], c[i];
}
}
' OFS=\| file.csv
"201707"|"51976551"|2|0|2
"201707"|"51960597"|1|0|0
"201707"|"51923555"|2|0|2
"201707"|"51955194"|2|0|0
工作原理
-F"|"
这会将输入的字段分隔符设置为
|
。a[ OFS ]+=; b[ OFS ]+=; c[ OFS ]+=
这会跟踪第三、第四和第五列的总数。
END { for (i in a) { print i, a[i], b[i], c[i]; } }
这会打印出结果。
OFS=\|
这告诉 awk 使用
|
作为输出的字段分隔符。
要保留顺序:
在END块中处理
awk 'BEGIN{
FS=OFS="|"
}
{
k = OFS ;
if(!(k in t)){
o[++c]=k;
t[k]
}
for(i=3; i<=5; i++)
a[k OFS i]+=$i
}
END{
for(i=1; i in o; i++)
{
printf "%s", o[i];
for(j=3; j<=5; j++)
printf "%s%s", OFS, a[o[i] OFS j];
print ""
}
}
' infile
或者通过读取同一个文件两次 (GNU awk)
awk 'BEGIN{
FS=OFS="|"
}
function ps(f)
{
for(i=3;i<=5;i++)
if(f)
{
a[k OFS i]+=$i;
t[k]
}else
s=(s ? s OFS :"") a[k OFS i]
}
{
k= OFS
}
FNR==NR{
ps(1);
next
}
k in t{
s="";
ps();
print k, s;
delete t[k]
}
' infile infile
输入:
$ cat input
"201707"|"51976551"|1|0|1|"20170702"
"201707"|"51955194"|1|0|0|"20170702"
"201707"|"51923555"|1|0|1|"20170702"
"201707"|"51976551"|1|0|1|"20170703"
"201707"|"51955194"|1|0|0|"20170703"
"201707"|"51923555"|1|0|1|"20170703"
"201707"|"51960597"|1|0|0|"20170703"
输出-1:
$ awk 'BEGIN{FS=OFS="|"}{k = OFS ; if(!(k in t)){o[++c]=k; t[k]} for(i=3; i<=5; i++)a[k OFS i]+=$i}END{for(i=1; i in o; i++){printf "%s", o[i]; for(j=3; j<=5; j++)printf "%s%s", OFS, a[o[i] OFS j]; print ""}}' infile
"201707"|"51976551"|2|0|2
"201707"|"51955194"|2|0|0
"201707"|"51923555"|2|0|2
"201707"|"51960597"|1|0|0
输出 2:
$ awk 'BEGIN{FS=OFS="|"}function ps(f){for(i=3;i<=5;i++)if(f){ a[k OFS i]+=$i; t[k] }else s=(s ? s OFS :"") a[k OFS i]}{k= OFS }FNR==NR{ps(1); next}k in t{s=""; ps(); print k, s; delete t[k] }' infile infile
"201707"|"51976551"|2|0|2
"201707"|"51955194"|2|0|0
"201707"|"51923555"|2|0|2
"201707"|"51960597"|1|0|0