助けてください?私には任務がある。数字を含むテキストを入力しました。たとえば、
beta 1
score 9
something 2
beta 4
something 1
周囲に同じテキストを含むすべての数字を数える必要があります。私の出力は次のとおりです。 (このように「:」を使用してください)
beta:5
something:3
score:9
さらに、スコアを保存する一時ファイルに問題がある可能性があります。mktemp
スクリプトが完了したら削除するために使用する必要があります。助けてくれてありがとう。
答え1
入力には常に1行に2つのフィールドが含まれていると仮定します。
GNUユーティリティを使用してdatamash
データをソートし、最初のフィールドでグループ化し、各グループの2番目のフィールドの合計を計算できます。
datamash -s -W --output-delimiter=: groupby 1 sum 2 <file
ここでは、ユーティリティーは連続した空白文字をフィールド区切り文字として扱い、出力区切り文字を対応する文字に設定するように-s
入力をソートします。残りは、最初のフィールドに基づいてグループ化し、各グループの2番目のフィールドの合計を計算するように指示します。-W
--output-delimiter=:
:
datamash
というファイルの問題への入力が与えられると、次のfile
ような出力が生成されます。
beta:5
score:9
something:3
他の多くの方法でもこの問題を解決できます。最も簡単な計算ソリューションは、次のものを使用することですawk
。
awk '{ sum[$1] += $2 } END { for (key in sum) printf "%s:%d\n", key, sum[key] }' file
sum
ここでは、最初のフィールドの各文字列の合計を維持するために連想配列を使用します。このEND
ブロックは入力の終わりに実行され、計算された合計を文字列と共に出力します。
また、この解決策は、質問に示すように、最初のフィールドが空白文字を含まない単一の単語であると仮定します。
シェルループを使用してソースファイルからソートされた行を読み取り、新しい最初のフィールドが表示されるたびに2番目のフィールドの合計を印刷してリセットします。
unset -v prev
sort file |
{
while read -r key value; do
if [ "$key" != "${prev-$key}" ]; then
# prev is set and different from $key
printf '%s:%d\n' "$prev" "$sum"
sum=0
fi
prev=$key
sum=$(( sum + value ))
done
if [ "${prev+set}" = set ]; then
printf '%s:%d\n' "$prev" "$sum"
fi
}
答え2
大容量ファイルを処理する場合は、キーと値を格納するためにRAMに巨大な配列を割り当てないようにして使用することをsort
検討してください。awk
λ cat input.txt
beta 1
score 9
something 2
beta 4
something 1
sort input.txt |
awk -v OFS=: 'NR==1{ key=$1 }; NR>1&&$1!=key{ print key, sum; sum=0; key=$1 }; {sum+=$2} END{ print key, sum}'
beta:5
score:9
something:3
答え3
#!/bin/bash
declare -i SECOND
while read first second; do
if [ -z $FIRST ] || [ $first = $FIRST ]; then
SECOND+=second
else
echo $FIRST:$SECOND
SECOND=second
fi
FIRST=$first
done < <(sort file)
echo $FIRST:$SECOND
通常、私は同様のスペースを作成し、本番環境ですべての変数を引用符で囲みます。
答え4
for k in $(awk '{if(!seen[$1]++)print $1}' file.txt); do awk -v k="$k" 'BEGIN{sum=0}$0 ~ k {sum=sum+$2}END{print k,sum}' file.txt; done
出力
beta 5
score 9
something 3