1. 概要

このチュートリアルでは、Bashシェルで数値の列を合計する方法を学習します。 この目的に使用できるBashユーティリティのいくつかを詳しく見ていきます。提供されているソリューションのパフォーマンスのベンチマークも行います

2. 設定

まず、ほとんどのチュートリアルで使用する入力ファイルを設定しましょう。

$ for i in `seq 1000000`; do echo $(($RANDOM%100)); done >numbers.csv

ここでは、ファイルnumbers.csvを生成しています。このファイルには、1〜100の範囲内の100万個のランダムな数値が含まれています。 seq コマンドを使用して、 for ループを実行し、RANDOM組み込み変数を使用して1,000,000個の数値を生成しています。

次のセクションでは、 time コマンドを使用して提供されるソリューションのローカル速度を確認し、各コマンドの実行方法を確認します。

3. awkツールの使用

awk コマンドから始めて、列の数値の合計を計算しましょう。

$ awk '{Total=Total+$1} END{print "Total is: " Total}' numbers.csv
Total is: 49471228

それでは、timeコマンドを使用して実行時間を見てみましょう。

$ time awk '{Total=Total+$1} END{print "Total is: " Total}' numbers.csv
Total is: 49471228

real    0m0.228s
user    0m0.141s
sys     0m0.047s

かなり速いです! 0.228秒で100万個の数字の合計を計算できます 。 実際、 awk は、ファイル処理のためのBashで最も強力なツールの1つです。

3.1. ファイルに複数の列が含まれている場合

これまでのところ、awkを使用して列の数値を合計する方法を知っています。 ファイルに複数の列があり、特定の列の合計のみを計算することに関心がある場合を見てみましょう。

$ cat prices.csv
Books,40
Bag,70
Dress,80
Box,10

ここで、ファイルprices.csvには2つの列が含まれています。 次に、2番目の列の要素の合計を計算しましょう。

$ awk -F "," '{Total=Total+$2} END{print "Total is: " Total}' prices.csv
Total is: 200

3.2. ファイルにヘッダー行が含まれている場合

場合によっては、テキストファイルまたはCSVファイルにヘッダー行が含まれることもあります。 このヘッダー行は、読みやすくするために、通常、列名を保持します。 prices.csv を変更して、ヘッダー行を追加しましょう。

$ cat prices.csv
Item,Value
Books,40
Bag,70
Dress,80
Box,10

ファイルにヘッダー行が含まれている場合、テキスト処理が行われる前にこのヘッダー行を削除する必要があります。 これを達成するためのいくつかの方法があります。 この場合、awkツールを使用してヘッダー行を無視します。 それでは、先に進み、コマンドを変更して列の合計を計算しましょう。

$  awk -F "," 'NR!=1{Total=Total+$2} END{print "Total is: " Total}' prices.csv
Total is: 200

次のセクションでは、列の数値を合計する他のいくつかの方法を確認し、awkソリューションがそれらの方法と比較してどのように機能するかを評価します。

4. バッシュループで反復する

awk は優れたツールですが、ループを使用して列の値を反復処理することもできます。

4.1. exprコマンドの使用

実験を実行し、 expr コマンドの有効性を確認して、forループ内の合計を計算してみましょう。

$ time (sum=0;for number in `cat numbers.csv`; do sum=`expr $sum + $number`; done; echo "Total is: $sum")
Total is: 49471228

real    212m48.418s
user    7m19.375s
sys     145m48.203s

処理はひどく遅かった。 exprコマンドを使用すると、100万個の数値を追加するのに3.5時間以上かかりました。 特に、 expr ユーティリティはBashの初期からの遺物であり、スクリプトをレガシー(POSIX以前)の実装と相互運用する必要がある場合にのみ使用する必要があります。

4.2. 算術展開の使用

expr コマンドの使用はあまり役に立たなかったので、算術展開を使用した別のアプローチを試してみましょう。

$ time (sum=0;for number in `cat numbers.csv`; do sum=$((sum+number)); done; echo "Total is: $sum")
Total is: 49471228

real    0m1.961s
user    0m1.813s
sys     0m0.125s

ここで、は、算術展開 と$((..))形式を使用して合計を計算しています。 exprコマンドとは異なり、算術展開を使用すると、2秒以内に100万個の数値を追加できました。算術展開により、単純な整数演算を実行できます。 ただし、浮動小数点数では機能しません。 したがって、浮動小数点演算の場合、bcコマンドを使用する必要があります。 次のセクションでは、bcコマンドの実装を確認します。

5. bcコマンドを使用した値の追加

bc コマンドは、1行の式で計算を実行します。 したがって、加算演算子で区切って、数値を1行にまとめる必要があります。 次に、式を bc に渡して、合計を計算します。 これを達成するためのいくつかの方法を見てみましょう。

5.1. pastコマンドの使用

まず、貼り付けコマンドを見て、データセットの最初の10個の数値を1行に配置し、それらの間にプラス(+)演算子を付けます

$ cat numbers.csv| head -10 | paste -sd+ - 
2+44+6+15+23+0+15+88+82+1

オプション-sは、貼り付けがすべての数値を1行に結合することを保証します。 また、は、エントリの結合中に区切り文字として「+」文字を追加するd+オプションを指定しました。

これで、このシーケンスをstdinとしてbcコマンドに提供する準備が整いました。

$ time echo "Total is: $(cat numbers.csv | paste -sd+ - | bc)"
Total is: 49471228

real    0m0.244s
user    0m0.203s
sys     0m0.063s

特に、 パフォーマンスは、Bashループで観察されたものよりも優れています(約2秒)。 また、接近しましたが、awkコマンドのパフォーマンス(0.228秒)に勝るものはありませんでした。

5.2. trコマンドの使用

past コマンドと同様に、trコマンドを使用してシーケンスを再度生成してみましょう。

$ cat numbers.csv | head -10 |tr "\n" "+"
2+44+6+15+23+0+15+88+82+1+

ここでは、各改行(’\ n’)をプラス(’ +’)文字に変換しました。 ただし、シーケンスの最後に余分な‘+’があることに注意してください。 回避策として、 bc コマンドに渡す前に、これを処理するために最後にゼロを追加することができます。

$ cat numbers.csv | head -10 |tr "\n" "+" ; echo "0"
2+44+6+15+23+0+15+88+82+1+0

次に、出力をbcコマンドにリダイレクトしましょう。

$ time ((cat numbers.csv | tr "\n" "+" ; echo "0") | bc)
49471228

real    0m0.217s
user    0m0.203s
sys     0m0.031s

trコマンドとbcコマンドの組み合わせは、awkソリューションよりも高速に実行されます。

5.3. sedコマンドの使用

最後に、sedコマンドを使用してシーケンスを生成します。

 $ cat numbers.csv | head -10 | sed -z 's#\n#+#g'
2+44+6+15+23+0+15+88+82+1+

ここでも、 search and replace オプションを使用して、改行(’\ n’)をプラス(’ +’)文字に置き換えました。 sedコマンド。 また、前のセクションと同様に、余分なプラス演算子を処理するために最後にゼロを出力しています。

$ time ((cat numbers.csv | sed -z 's#\n#+#g' ; echo "0") | bc)
49471228

real    0m0.343s
user    0m0.281s
sys     0m0.109s

ここで、 -z オプションを使用すると、sedコマンドの改行の意味が変わります。 \ n は行の終わりとは見なされなくなり、代わりにヌル文字が行の終わりとして解釈されます。 実際には、改行(’\ n’)をプラス(’ +’)文字に置き換えることができます。

文字をsedに置き換えるのは、trおよび貼り付けオプションと比較して遅いことに注意してください。

結論を出す前に、 awk 以外の代替案は、単一の数値列を含むファイルの方が高速に実行される可能性があることに注意する必要があります。 ただし、多くの実際のシナリオでは、ファイルには複数の列が含まれ、実際の計算が行われる前に、いくつかの追加情報が削除されます(セクション3.1での説明と多少似ています)。

このような場合、 awkは頼りになるツールです。これは、awk以外の代替手段の速度の利点はすべて、ファイルを前処理して単一の列を抽出するためにを計算する前にかかる時間によって消費されるためです。その要素の合計。

6. 結論

このチュートリアルでは、Bashシェルで数値の列を合計する方法について説明しました。

まず、awkツールを使用してソリューションについて説明しました。 さらに、複数の列またはヘッダー行を含むファイルを処理する方法についても検討しました。

次に、Bashループを使用してソリューションを実装しました。 最後に、 tr past 、およびを使用して数値を単一行の式に変換することにより、bcコマンドを使用して合計を計算する手法を示しました。 ]sedユーティリティ。