grep 具有不同数量的匹配组的多个模式?

jaw*_*317 4 grep awk regular-expression pattern-matching

我正在尝试统计 git diff 的插入和删除。

我有以下内容,当通过管道传输一个或多个形式的字符串时"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 }'
Run Code Online (Sandbox Code Playgroud)

这会产生insertions: 629607 deletions: 123

然而,有时 diff 并不遵循上述格式,而是只有插入或只有删除。

在这些情况下,我不需要匹配两个数字,而只需要匹配一个(并确保它最终出现在右列中)。

如何创建一个足够灵活的正则表达式来处理这些变化,并且生成可以awk正确计数的输出?

Gil*_*not 8

我在这里使用它是Perl为了灵活性、可读性和可移植性,没有复杂的正则表达式,让我们KISS(......我只使用来自 的一个管道git)。

它在任何情况下都有效:有或没有模式之一,否则这将跳过根本不匹配的行:

$ git diff
7 insertions, 1 deletions
1 deletions
3 insertions
foobar
Run Code Online (Sandbox Code Playgroud)
$ 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"}
'
Run Code Online (Sandbox Code Playgroud)
10 insertions, 2 deletions
Run Code Online (Sandbox Code Playgroud)


Dan*_*Dan 6

其他发帖者已经回答了如何直接解决您的问题。但是,既然您提到您正在解析 的结果git diff,我建议采用稍微不同的方法。

如果您想在脚本中使用 的输出diff,可以使用--numstat代替--stat

您最终将得到一致的输出,因为其目的--numstat是用于脚本。

使用时git diff --stat,您会得到以下输出:

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

使用时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
Run Code Online (Sandbox Code Playgroud)

上面的结构只是一个三列结构。第一列是插入次数,第二列是删除次数,最后一列是文件名。

您可以通过管道传输命令来汇总列,而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
Run Code Online (Sandbox Code Playgroud)

更多链接:git-diff 手册页/其他 diff 格式


ilk*_*chu 5

grep并没有真正提供捕获组的良好视图,所以我在这里切换到 Perl。通过此测试输入foo.txt

2 files changed, 2 insertions(+), 7 deletions(-)
1 file changed, 9 deletions(-)
garbage
1 file changed, 10 insertions(+)
Run Code Online (Sandbox Code Playgroud)

你可以这样做:

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

或者也用 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
Run Code Online (Sandbox Code Playgroud)

这里的要点是,用于插入的组在?其后面是可选的,并且捕获组的编号从左到右,无论它们是否匹配。再加上一些捏造,以便所有三种可能的输入格式都匹配。当然,您也可以针对/, (\d+) insertion/和进行两场单独的比赛/, (\d+) deletion/,等等。