Linux 总结 a table 并对每个给定事件的所有列求和
Linux summary a table and sum all columns from each given occurrence
完成分析后,我得到一个包含很多列和行的 table。此外,随着新的 table 的写入,lines/cols 的数量可能会有所不同,因此我无法预测每个会有多少。每行在第一列中都有一个索引,但这些索引可以在 table 中重复。所以我想要的是一种 grep/awk/bash 方法来检索具有相同索引的所有这些行并对所有列求和以仅获得具有求和值的一行。
举个例子:
table
index,sampleA,sampleB,sampleC
nana,22,12,4
baba,47,4,5
nana,1,5,9
nana,7,5,8
解析后
index,sampleA,sampleB,sampleC
nana,30,22,21
baba,47,4,5
如果你能帮助我,我将不胜感激。
非常感谢。
有点啰嗦,但像这样就可以了:
awk -F"," 'BEGIN{OFS=FS} NR==1{print [=10=]; next} NR>1{sampleA[]+=; sampleB[]+=; sampleC[]+=}END{for (sample in sampleA){print sample, sampleA[sample], sampleB[sample], sampleC[sample]}}' yourfile
解释:
- 用逗号分隔每一行
-F","
- 在处理文件之前确保输出字段分隔符与字段分隔符(逗号)相匹配
BEGIN{OFS=FS}
- 如果这是文件的第一行然后打印出来(它是header)然后继续下一行
NR==1{print [=13=]; next}
- 如果这不是 header 行,则创建三个数组来存储第 2、3、4 列的累积值。数组的 "key" 是第 1 列中的值
NR>1{sampleA[]+=; sampleB[]+=; sampleC[]+=}
- 最后,循环遍历三个数组中的第一个(它们的长度都相同,所以我们只需要循环一个)。然后打印出存储在每个键中的值:
END{for (sample in sampleA){print sample, sampleA[sample], sampleB[sample], sampleC[sample]}}
您没有指定 shell,但如果您喜欢使用 ksh (93l+),那也应该可以解决问题。
虽然这个脚本做了一些假设:
- 可以有任意数量的列,但每行的列数相同
- 索引名称中没有space
每列总有一个值
#!/bin/ksh
# CSV to input as first argument, CSV to ouput as second argument
InputCSV=
OutputCSV=
typeset -A Index
while read line; do
lineArray=(${line//,/ })
# Assume that the first column is always named "index", but you can modify this
if [[ ${lineArray[0]} == "index" ]]; then
titleArray=(${line//,/ })
continue
fi
for ((i=1;i<${#lineArray[*]};i++)); do
if [[ -z ${Index[${lineArray[0]}][${titleArray[$i]}]} ]]; then
Index[${lineArray[0]}]+=( [${titleArray[$i]}]=${lineArray[$i]} )
else
Index[${lineArray[0]}][${titleArray[$i]}]=$(( ${Index[${lineArray[0]}][${titleArray[$i]}]} + ${lineArray[$i]} ))
fi
done
done < $InputCSV
exec 3>$OutputCSV
titleBar=${titleArray[0]}
for ((i=1;i<${#titleArray[*]};i++)); do
titleBar+=",${titleArray[$i]}"
done
print $titleBar >&3
for j in ${!Index[@]}; do
outLine=$j
for ((i=1;i<${#titleArray[*]};i++)); do
outLine+=",${Index[$j][${titleArray[$i]}]}"
done
print $outLine >&3
done
exec 3>&-
完成分析后,我得到一个包含很多列和行的 table。此外,随着新的 table 的写入,lines/cols 的数量可能会有所不同,因此我无法预测每个会有多少。每行在第一列中都有一个索引,但这些索引可以在 table 中重复。所以我想要的是一种 grep/awk/bash 方法来检索具有相同索引的所有这些行并对所有列求和以仅获得具有求和值的一行。 举个例子:
table
index,sampleA,sampleB,sampleC
nana,22,12,4
baba,47,4,5
nana,1,5,9
nana,7,5,8
解析后
index,sampleA,sampleB,sampleC
nana,30,22,21
baba,47,4,5
如果你能帮助我,我将不胜感激。 非常感谢。
有点啰嗦,但像这样就可以了:
awk -F"," 'BEGIN{OFS=FS} NR==1{print [=10=]; next} NR>1{sampleA[]+=; sampleB[]+=; sampleC[]+=}END{for (sample in sampleA){print sample, sampleA[sample], sampleB[sample], sampleC[sample]}}' yourfile
解释:
- 用逗号分隔每一行
-F","
- 在处理文件之前确保输出字段分隔符与字段分隔符(逗号)相匹配
BEGIN{OFS=FS}
- 如果这是文件的第一行然后打印出来(它是header)然后继续下一行
NR==1{print [=13=]; next}
- 如果这不是 header 行,则创建三个数组来存储第 2、3、4 列的累积值。数组的 "key" 是第 1 列中的值
NR>1{sampleA[]+=; sampleB[]+=; sampleC[]+=}
- 最后,循环遍历三个数组中的第一个(它们的长度都相同,所以我们只需要循环一个)。然后打印出存储在每个键中的值:
END{for (sample in sampleA){print sample, sampleA[sample], sampleB[sample], sampleC[sample]}}
您没有指定 shell,但如果您喜欢使用 ksh (93l+),那也应该可以解决问题。
虽然这个脚本做了一些假设:
- 可以有任意数量的列,但每行的列数相同
- 索引名称中没有space
每列总有一个值
#!/bin/ksh # CSV to input as first argument, CSV to ouput as second argument InputCSV= OutputCSV= typeset -A Index while read line; do lineArray=(${line//,/ }) # Assume that the first column is always named "index", but you can modify this if [[ ${lineArray[0]} == "index" ]]; then titleArray=(${line//,/ }) continue fi for ((i=1;i<${#lineArray[*]};i++)); do if [[ -z ${Index[${lineArray[0]}][${titleArray[$i]}]} ]]; then Index[${lineArray[0]}]+=( [${titleArray[$i]}]=${lineArray[$i]} ) else Index[${lineArray[0]}][${titleArray[$i]}]=$(( ${Index[${lineArray[0]}][${titleArray[$i]}]} + ${lineArray[$i]} )) fi done done < $InputCSV exec 3>$OutputCSV titleBar=${titleArray[0]} for ((i=1;i<${#titleArray[*]};i++)); do titleBar+=",${titleArray[$i]}" done print $titleBar >&3 for j in ${!Index[@]}; do outLine=$j for ((i=1;i<${#titleArray[*]};i++)); do outLine+=",${Index[$j][${titleArray[$i]}]}" done print $outLine >&3 done exec 3>&-