Awk 使用shell按对象汇总一个列表,其中包含总计
我不熟悉sh shell脚本。 如何根据Awk 使用shell按对象汇总一个列表,其中包含总计,awk,bash,shell,unix,sort,sed,bc,cut,ksh,dash,busybox,Awk,Bash,Shell,Unix,Sort,Sed,Bc,Cut,Ksh,Dash,Busybox,我不熟悉sh shell脚本。 如何根据sort和grep编写此脚本 有一个按组汇总列表所有值的脚本 awk '{ arr[$1]+=$2 } END { for (key in arr) printf("%s\t%s\n", key, arr[key]) }' "$@" | sort +0n -1 假设文件: A 8 B 3 A 2 B 4 输出为: A 10 B 7 我现在所拥有的就是cat“$1”| sort,但是如何在不使用awk的情况下分别获得左
sort
和grep
编写此脚本
有一个按组汇总列表所有值的脚本
awk '{ arr[$1]+=$2 }
END {
for (key in arr) printf("%s\t%s\n", key, arr[key])
}' "$@" |
sort +0n -1
假设文件:
A 8
B 3
A 2
B 4
输出为:
A 10
B 7
我现在所拥有的就是cat“$1”| sort
,但是如何在不使用awk
的情况下分别获得左右列呢
我一直在想如何将第一列分别放入右边的数组中。假设您有
bash
4.x或足够新的ksh
,您可以尝试:
declare -A sum # Use typeset -A sum in ksh, which also works in bash
cat <<'EOF' |
A 8
B 3
A 2
B 4
EOF
{
while read key value
do
((sum[$key]+=$value))
done
for key in "${!sum[@]}"
do echo "$key ${sum[$key]}"
done
} | sort
declare-A sum#使用typeset-A sum-in ksh,它也适用于bash
猫
第一个sed表达式以A=$($A+8))
的形式创建行。第二个生成echo“A=$A”代码>表达式
给出:
使用纯
没有外部工具和叉子:非常快(在处理小文件时)
这将存储包含以下内容的关联数组:
set | grep ^values=
values=([A]="10" [B]="7" )
您可以使用以下方法进行转储:
for name in ${!values[@]};do
printf "%s: %s\n" $name ${values[$name]}
done
A: 10
B: 7
使用POSIX++
Nota:这样做可能会更好地使用对以美元为单位的var(…)
如本答案最后一部分中建议的那样,另一个shell答案仅使用sed
其中我使用sed
构建两行代码提交给bc
:
sort <file |
sed '
:a;
$!N;
s/^\(.*\) \(.*\)\n\1 \(.*\)/\1 \2+\3/;
ta;
s/^\([^ ]*\) \([^\n]*\)\($\|\n\)/"\1 ";\2;\3/;
P;
D;
'|
bc
A 10
B 7
兼容答案(使用和)
如果目标是在shell脚本级别处理结果:
(这是在和下测试的)
其中,varname是${var%=*}
,并且通过符号+
合并的值位于${var%*=}
中:
sed -ne < file '
x; # swap crt line and hold space
G; # append hold space to crt line
/\(.\)=.*\n\1/ ! s/^\(.*\)\n\(.\) \(.*\)$/\1 \2=\3 /; # if not find, append
s/\(.\)=\(.*\)\n\1 \(.*\)/\1=\3+\2/; # add `+` + crt value at right place
x; # swap crt line and hold space
${ # on last line
x; # swap crt line and hold space
p # print
}' # that's all folks!
A=2+8 B=4+3
sed-ne
我相信使用awk
不会让它以任何方式变得更简单。我可以知道你为什么要避免使用awk
?我只是好奇如果不使用awk
,这将如何工作,但我很难做到这一点。所以你希望我们在你的任意规则下找到一种可接受的方法?我可以使用perl吗?此外,如果awk
不可接受,您可能应该将其从标记列表中删除。对A
和B
进行数字排序似乎有些奇怪。我对使用shell脚本更感兴趣。我将从标记列表中删除awk
。这意味着您没有使用bash
4.x(或者您将其用作/bin/sh
,在这种情况下,它可能无法识别declare
)。你用的是哪个外壳?如果您使用的是ksh
(Korn Shell),则需要使用排版
,而不是声明
,如答案中所述。如果您使用的是csh
或tcsh
或类似的东西,那么您就处于一种无所遁形的状态。如果您使用的是原始Bourne shell,那么您将处于一种“无所遁形”的状态。如果您使用的是zsh
,那么它应该是各种shell的所有歌唱、所有舞蹈的扩展;我有一半的希望它能起作用,但我不知道该怎么说。哦,如果你没有收集到,所有的贝壳都是不相等的。有些人比其他人更强大。如果您想要可靠性和可移植性,您将继续使用awk
。如果shell不支持关联数组,则将继续使用awk
。实际上,无论如何,您可能会使用awk。但你问我怎么做,我用正确的炮弹演示了怎么做。我在Mac OS X 10.9.1上测试了bash
4.2和ksh
(sh(AT&T研究)93u 2011-02-08
)。ksh
由苹果公司提供;我自己制作了bash
,以防其他人也好奇:“无所事事”是一个英国成语,意思是“不可能成功,或者如果成功了就不可能获得太多好处”bash
作为sh
调用时,至少在OS X上原则上可以识别declare
。v4之前的bash
-不支持关联数组-将投诉declare:-A:无效选项
。若要使代码在zsh
中工作,请将“${!sum[@]}”替换为${(k)sum}
@mklement0:hmmm……是的,我想英国成语可能需要翻译。感谢您提供有关zsh
语法的信息。
for name in ${!values[@]};do
printf "%s: %s\n" $name ${values[$name]}
done
A: 10
B: 7
sort <file |
sed '
:a;
$!N;
s/^\(.*\) \(.*\)\n\1 \(.*\)/\1 \2+\3/;
ta;
s/^\([^ ]*\) \([^\n]*\)\($\|\n\)/"\1 ";\2;\3/;
P;
D;
'|
bc
A 10
B 7
"A ";2+8;
"B ";3+4;
for name in $(cut -d\ -f1 <file | sort -u) ;do
value=0
while read cnam cval ;do
[ "$cnam" = "$name" ] && value=$((cval+value))
done <file
printf "%s: %d\n" $name $value
done
A: 10
B: 7
for var in $(
sed -ne < file 'x;G;/\(.\)=.*\n\1/!s/^\(.*\)\n\(.\) \(.*\)$/\1 \2=\3 /;
s/\(.\)=\(.*\)\n\1 \(.*\)/\1=\3+\2/;x;${x;p}')
do
printf "%s: %3d\n" ${var%=*} $(( ${var#*=} ))
done
A: 10
B: 7
sed -ne < file '
x; # swap crt line and hold space
G; # append hold space to crt line
/\(.\)=.*\n\1/ ! s/^\(.*\)\n\(.\) \(.*\)$/\1 \2=\3 /; # if not find, append
s/\(.\)=\(.*\)\n\1 \(.*\)/\1=\3+\2/; # add `+` + crt value at right place
x; # swap crt line and hold space
${ # on last line
x; # swap crt line and hold space
p # print
}' # that's all folks!
A=2+8 B=4+3