抱歉,如果我打开一个新问题,但它与之前的问题无关,因为现在我需要一个bash命令来分析输出。
我有一个查询输出存储在这样的文件中:
3277654321 333011123456789
3277654321 333015123456789
3277654321 333103123456789
3277654321 333201123456789
3291234567 333991123456789
3291234567 333991123456789
3291234567 333011123456789
我需要的是一个bash命令来计算具有相同前5位数的field1和field2并报告这样的输出:
3277654321=4;33301=2;33310=1;33320=1
3291234567=3;33399=2;33301=1
由于 卢卡斯。
答案 0 :(得分:1)
awk
您正在寻求的是一个控制中断报告。一次,维基百科的条目对这个问题没什么帮助。样本数据按顺序显示;因此,该解决方案假定数据已排序(但如果未排序,则在awk
脚本之前添加排序操作是微不足道的; OTOH,因为数据来自数据库,所以DBMS可以很好地完成对数据进行排序。)
出于测试目的,我创建了一个包含以下内容的文件awk.script
{ f1 = $1
f2 = substr($2, 1, 5)
if (oldf1 != f1)
{
if (oldf1 != 0)
{
summary = summary ";" oldf2 "=" f2_count
printf("%s=%d%s\n", oldf1, f1_count, summary)
}
oldf1 = f1
f1_count = 0
oldf2 = f2
f2_count = 0
summary = ""
}
else if (oldf2 != f2)
{
summary = summary ";" oldf2 "=" f2_count
oldf2 = f2
f2_count = 0
}
f1_count++
f2_count++
}
END {
if (oldf1 != 0)
{
summary = summary ";" oldf2 "=" f2_count
printf("%s=%d%s\n", oldf1, f1_count, summary)
}
}
将七行示例数据放入名为data
的文件中,然后运行:
$ awk -f awk.script data
3277654321=4;33301=2;33310=1;33320=1
3291234567=3;33399=2;33301=1
$
目前,数据类似于查询的输出,例如:
SELECT Field1, Field2
FROM SomeTable
ORDER BY Field1, Field2
通过让DBMS生成第一个字段,第二个字段的前5个字符以及条目数的计数,可以使报告的输出更好:
SELECT field1, SUBSTR(field2, 1, 5) AS field2, COUNT(*) AS number
FROM SomeTable
GROUP BY field1, field2
ORDER BY field1, field2
然后通过网络传输的数据更少,如果数据库是远程的,这会有很大帮助。您还有一个更简单的报告。数据文件变为(data2
):
3277654321 33301 2
3277654321 33310 1
3277654321 33320 1
3291234567 33399 2
3291234567 33301 1
awk
脚本变为(awk.script2
):
{
if (oldf1 != $1)
{
if (oldf1 != 0)
printf("%s=%d%s\n", oldf1, f1_count, summary)
oldf1 = $1
f1_count = 0
summary = ""
}
summary = summary ";" $2 "=" $3
f1_count += $3
}
END {
if (oldf1 != 0)
printf("%s=%d%s\n", oldf1, f1_count, summary)
}
示例运行:
$ awk -f awk.script2 data2
3277654321=4;33301=2;33310=1;33320=1
3291234567=3;33399=2;33301=1
$
根据您的DBMS以及它是否支持子查询中的GROUP_CONCAT
和ORDER BY
条款,您可以注意到rici suggested“这不是那么混乱,恕我直言”
以下似乎在SQLite3中运行良好;对于MySQL,您需要将逗号更改为GROUP_CONCAT中的单词SEPARATOR:
SELECT field1 || "=" || SUM(count2) || ";" || group_concat(field2 || "=" || count2, ";") AS fields FROM (SELECT field1, SUBSTR(field2, 1, 5) AS field2, COUNT(*) AS count2 FROM tmp GROUP BY field1, field2 ORDER BY field1, field2 ) GROUP BY field1 ORDER BY field1
请注意,据我所知,子标查询中的GROUP_CONCAT
和ORDER BY
子句都不是由ISO标准SQL定义的,因此并非所有DBMS都支持这些功能。 (原因省略了ORDER BY功能,但推理不包括'正交性'的考虑因素。)
如果DBMS以您需要的格式生成数据,则不需要awk
脚本对其进行后处理。什么是最好的将最终取决于你正在做什么。通常,使用DBMS在有意义的地方进行计算。 IMO,不要将DBMS用于所有格式化 - 我希望报告生成与分页等在DBMS之外完成 - 但是如果可以说服它生成所需的数据,那么无论如何都要让它完成工作。 / p>
答案 1 :(得分:0)
人们,我想分享一个“优雅”的解决方案。感谢飞往其他社区用户,他们推动我建议一些步骤。
awk 'NR>0 {C1[$1]++
C2[$1,substr($2,1,5)]++
}
END {for (c2 in C2) {split (c2, cx, SUBSEP); print cx[1] "=" C1[cx[1]] ";" cx[2] "=" C2[c2]}}
' SUBSEP=";" out.txt | sort | awk '$1 != L {printf "%s%s", LT, $1; L=$1; LT="\n"}
{printf ";%s", $2}
END {printf "\n"}
' FS=";"
3277654321=4;33301=2;33310=1;33320=1
3291234567=3;33399=2;33301=1
而且rici,我不是要求有人为我编写代码。这只是一个大脚本的一小部分,所以我只是请求如何做一件小事的帮助。我对不同的方法感兴趣,这就是为什么我要求不提供任何代码示例。感谢所有参与此问题的SO用户,我仍然愿意尝试不同的方法。