いくつかの空白で区切られた単語と正の数字を含むテキストファイルがあります。
A dog has a ball number 49 number 34 number A
Cats number 58
...
文字列「number」の後に発生するすべての数字を合計したい。文字列の後の「数字」が数字でない場合、それは問題ではありません。
たとえば、この場合、答えは 49+34+58 になります141
。
いくつかの空白で区切られた単語と正の数字を含むテキストファイルがあります。
A dog has a ball number 49 number 34 number A
Cats number 58
...
文字列「number」の後に発生するすべての数字を合計したい。文字列の後の「数字」が数字でない場合、それは問題ではありません。
たとえば、この場合、答えは 49+34+58 になります141
。
awk '{ for (i = 1; i <= NF; i++) s = s+$i }; END { print s+0 }' test.txt
Awkはファイルを1行ずつ読み取ります。すべての行について、でマークされたブロック{}
が実行されます。ブロックは、条件によって保護できます。正規表現、...、およびBEGIN
、END
は、それぞれ最初の行と最後の行に対して「true」です。
これは、awkがすべての行の最初のブロックを実行することを意味します(保護されていないため)。
さらに、awkには実際には型システム(すべての文字列)がありません。ただし、文字列に算術演算を使用することはできます。その場合、文字列は魔法のように数値に変換されます。数値ではない文字列に対して算術演算を行うと、それらは「0」と評価されます。これは、次のことを意味します。 "asdf" + 1 = 1; 2 + 4 = 6; "asdf" + 0 = 0;
変数を宣言する必要はありません。デフォルトでは、数値が「0」の空の文字列になります。
awkの次の素晴らしさは、現在の入力行をフィールドに自動的に分割することです。フィールド区切り文字を指定できますが、デフォルトは空白です。$1
単一のフィールドには、、、$2
...でアクセスできます。$NF
つまりNF
、フィールドの数です。$0
完全な入力行の内容です。
そして、あなたはそれを持っています:あなたは現在の行のすべての「フィールド」を見ます。すべてのフィールド(文字列の場合は0)の数値は、変数に累積されますs
。すべて()を読み取った後END
、合計が出力されます。
編集:これは便利に機能するかもしれませんが、「番号」を考慮していないため、実際には質問に答えません-申し訳ありません。
修正:
awk '{ for (i = 1; i <= NF; i++) if ($i == "number") {s = s+$(++i)} }; END { print s+0 }' test.txt
そうすれば、次のような入力に対しても141になります。
10犬はボール番号49番号34番号A猫1000番号58を持っています
number
レコードセパレーターとして設定することにより、入力を awk で分離できます。
awk -v RS=number '{ sum += $1 } END { print sum }' infile
これは、grep、coreutils、および bc の代替手段です。
(<infile grep -Eoi 'number[[:blank:]]+[0-9]+' \
| tr -s '[:blank:]' | cut -d' ' -f2 | head -c -1 \
| tr '\n' '+'; echo
) | bc
出力:
141