Awk 使用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的情况下分别获得左

我不熟悉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
的情况下分别获得左右列呢


我一直在想如何将第一列分别放入右边的数组中。

假设您有
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