一致グループの数が異なる複数のパターンをgrepしますか?

一致グループの数が異なる複数のパターンをgrepしますか?

git diffで挿入と削除の数を数えようとしています。

1つ以上のフォーム文字列がパイプされたときに"4 files changed, 629607 insertions(+), 123 deletions(-)"合計を計算するには、次のものがあります。

grep -Eo 'changed, ?(\d+) insertion.*(\d+) deletion' | awk '{ i+=$2; d+=$4 } END { print "insertions: ",i," deletions: ",d }'

これは生産しますinsertions: 629607 deletions: 123

ただし、diffが上記の形式に従わずに挿入のみに従うか、削除のみに従う場合もあります。

この場合、2つの数字を一致させる必要はなく、1つだけ一致させる必要があります(そしてそれが正しい列にあることを確認してください)。

awkこれらのバリアントを処理し、正しく計算された出力を生成するのに十分な柔軟な正規表現を作成するにはどうすればよいですか?

答え1

ここでは柔軟性、可読性、移植性を使用しますPerl。複雑な正規表現は使用しません。KISS(...私はチューブを1つだけ使用しますgit。)

パターンの1つがあるかどうかにかかわらず、どんな場合でも機能します。それ以外の場合は、まったく一致しない行をスキップします。

$ git diff
7 insertions, 1 deletions
1 deletions
3 insertions
foobar
$ git diff | perl -nE '
    BEGIN{our $insert = our $delete = 0}
    $insert += $1 if /(\d+)\s+insertion/;
    $delete += $1 if /(\d+)\s+deletion/;
    END{say $insert . " insertions, " . $delete . " deletions"}
'
10 insertions, 2 deletions

答え2

他のポスターでは、問題を直接解決する方法についてすでに答えています。しかし、分析中の結果に言及したので、git diff少し異なるアプローチを提案します。

diffスクリプトで出力を使用するには、次を使用できます。--numstat変える--stat

スクリプトの目的で一貫した出力が生成されます--numstat

を使用すると、git diff --stat次のような結果が出力されます。

$ git diff main --stat
 [...list of files...]
 5 files changed, 112 insertions(+), 20 deletions(-)

を使用すると、git diff --statnum次のような結果が出力されます。

$ git diff main --statnum
-       -       some/binary/file
15      0       some/file
1       1       some/other/file
29      7       another/file
67      12      yet/another/file

上記の構造は3列構造です。最初の列は挿入回数、2 番目の列は削除回数、最後の列はファイル名です。

awk挿入および/または削除を心配することなく、コマンドをパイプして列を要約できます。

$ git diff main --numstat | awk '{sum_insertions+=$1;sum_deletions+=$2}END{print "insertions:", sum_insertions+0, "deletions:", sum_deletions+0;}'
insertions: 112 deletions: 20

追加リンク:git-diff マニュアルページ/その他 diff 形式

答え3

grepキャプチャグループの良いビューを実際に提供していないので、ここではPerlに切り替えました。次のテスト入力を渡しますfoo.txt

2 files changed, 2 insertions(+), 7 deletions(-)
1 file changed, 9 deletions(-)
garbage
1 file changed, 10 insertions(+)

次のことができます。

$ perl -ne '/files? changed, (?:(\d+) insertion\S*)? ?(?:(\d+) deletion)?/ && printf "%d %d\n", $1, $2' < foo.txt
2 7
0 9
10 0

あるいは、Perl を使用して合計を計算することもできます。

$ perl -ne 'if (/files? changed, (?:(\d+) insertion\S*)? ?(?:(\d+) deletion)?/) { $i += $1; $d += $2 } END { printf "insertions: %d deletions: %d\n", $i, $d }' < foo.txt
insertions: 12 deletions: 16

ここで重要なのは、挿入に使用されるグループは?その後のオプションであり、キャプチャグループは一致するかどうかに関係なく左から右に番号が付けられることです。また、3つの可能な入力フォーマットがすべて一致するように、少しパージを行います。もちろん、および/, (\d+) insertion/に対して2つの別々の一致を実行することもできます。/, (\d+) deletion/

答え4

GNU awkソリューションは基本的にPerlと同じです。

gawk -F'\n' '
  match($0, /([0-9]+)\s+insertion/, i) { total_i += i[1]; }
  match($0, /([0-9]+)\s+deletion/, d) { total_d += d[1]; }
  END {
    printf("insertions: %d  deletions: %d\n", total_i, total_d);
  }
'

POSIX awkにはキャプチャグループはありませんが、追加のsplit()手順を避けるために、awkを使用して一致する文字列の最初の数値部分を使用し、数値計算から残りの部分を自動的に削除できます。つまり、「3つの挿入」を追加すると追加が発生します。 「サム」。

awk -F'\n' '
  match($0, /[[:digit:]]+[[:space:]]+insertion/) {
    total_i += substr($0, RSTART, RLENGTH)
  }
  match($0, /[[:digit:]]+[[:space:]]+deletion/) {
    total_d += substr($0, RSTART, RLENGTH)
  }
  END {
    printf "insertions: %d  deletions: %d\n", total_i, total_d
  }
'

POSIX以前のawkがある場合は、新しいawkを購入してください。しかし、何らかの理由でこれが不可能な場合は、and to[[:digit:]]に変更するとすべてのawkで動作します(もちろん古い壊れたawkは除く)。[0-9][[:space:]][ \t]

関連情報