0

次のようなファイル(ソート済み)があります。

alma-court, 1, 0, 8
alma-court, 4, 2, 24
atlantic-house, 99, 1, 340
diamond, 2, 2, 16
iminds-zuiderpoort, 0, 1, 0
north-plaza, 18, 3, 718
north-plaza, 90, 2, 19

同じ最初の列ごとに垂直方向の合計を作成したいと思います。

alma-court については、1+4、0+2、8+24 の合計を取得したいと思います。atlantic-house は、これが唯一のオカレンスであるため、すでに問題ありません。また、north-plaza は 18+90、3+2、および 718+19 である必要があります。

そして、次のようにすべてを印刷します。

alma-court, 5, 2, 32
atlantic-house, 99, 1, 340
...

誰かが Bash を使って解決策を教えてくれませんか?

ありがとう。

4

3 に答える 3

2

これをベースとして使用できます。bash script

set -u
tr -d "," < data2 | while read name col1 col2 col3 ; do
    echo name=$name col1=$col1 col2=$col2 col3=$col3
done

data2ソートされたファイルはどこにありますか。

次の結果が得られ、そこから「名前」の変更を検出して計算できるはずです。

name=alma-court col1=1 col2=0 col3=8
name=alma-court col1=4 col2=2 col3=24
name=atlantic-house col1=99 col2=1 col3=340
name=diamond col1=2 col2=2 col3=16
name=iminds-zuiderpoort col1=0 col2=1 col3=0
name=north-plaza col1=18 col2=3 col3=718
name=north-plaza col1=90 col2=2 col3=19

これらのことは通常、Perl/Python/Awk でより適切に行われます。


完全を期すために EDIT に Perl バージョンが追加されました。


use strict;
my %names;
while(<>) {
    my @F = split(',');
    my $name = shift @F;
    foreach my $x (0..$#F) {
        $names{$name}[$x] += $F[$x];
    }
}
foreach my $key ( sort keys %names ){
    print $key, " ", join(" ", @{$names{$key}}), "\n";
}

as Give を使用perl myperl.pl < yourdataする

alma-court 5 2 32
atlantic-house 99 1 340
diamond 2 2 16
iminds-zuiderpoort 0 1 0
north-plaza 108 5 737
于 2013-02-15T23:55:37.150 に答える
1

以下を使用しますawk(Perl または Python を知っている、または学習したい場合を除きます):

awk '{ sum[$1,0] += $2; sum[$1,1] += $3; sum[$1,2] += $4; names[$1] = 1; }
     END { for (name in names)
               printf "%s %d, %d, %d\n", name, sum[name,0], sum[name,1], sum[name,2];
         }' <<EOF
alma-court, 1, 0, 8
alma-court, 4, 2, 24
atlantic-house, 99, 1, 340
diamond, 2, 2, 16
iminds-zuiderpoort, 0, 1, 0
north-plaza, 18, 3, 718
north-plaza, 90, 2, 19
EOF

出力:

iminds-zuiderpoort, 0, 1, 0
alma-court, 5, 2, 32
north-plaza, 108, 5, 737
atlantic-house, 99, 1, 340
diamond, 2, 2, 16

名前を特定の順序で並べたい場合は、出力を並べ替えます。名前には末尾のコンマが含まれているため、印刷形式では名前の後にコンマが追加されないことに注意してください。


純粋なbash(4.x) 実装

{
declare -A sum
declare -A names

IFS=,
while read name v1 v2 v3
do
    names[$name]="$name"
    ((sum[${name}1] += $v1))
    ((sum[${name}2] += $v2))
    ((sum[${name}3] += $v3))
done 

for name in "${names[@]}"
do
    printf "%s, %d, %d, %d\n" $name ${sum[${name}1]} ${sum[${name}2]} ${sum[${name}3]}
done
} <<EOF
alma-court, 1, 0, 8
alma-court, 4, 2, 24
atlantic-house, 99, 1, 340
diamond, 2, 2, 16
iminds-zuiderpoort, 0, 1, 0
north-plaza, 18, 3, 718
north-plaza, 90, 2, 19
EOF

出力:

diamond, 2, 2, 16
atlantic-house, 99, 1, 340
north-plaza, 108, 5, 737
alma-court, 5, 2, 32
iminds-zuiderpoort, 0, 1, 0

幸いなことに、awkbashスクリプトの出力は同じで、データの並べ替え順序を指定または取得します。

スクリプトは、3.xには存在しない 4.xbashの機能である連想配列を使用しています。bashbash

于 2013-02-16T00:48:16.733 に答える
0
groups=( $( cut -d ',' -f 1 count.txt | sort -u ) )

for group in "${groups[@]}"
do
  grep $group count.txt | awk '{ sum1+=$2; sum2+=$3; sum3+=$4;} END {print $1 " " sum1 ", " sum2 ", " sum3}'
done

anew@buddha:~/dev/so$ bash so.sh 
alma-court, 5, 2, 32
atlantic-house, 99, 1, 340
diamond, 2, 2, 16
iminds-zuiderpoort, 0, 1, 0
north-plaza, 108, 5, 737
于 2013-02-16T01:08:53.097 に答える