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 }'
이것은 생산할 것입니다insertions: 629607 deletions: 123
그러나 diff가 위의 형식을 따르지 않고 삽입만 따르거나 삭제만 따르는 경우도 있습니다.
이 경우 두 개의 숫자를 일치시킬 필요는 없고 하나만 일치시킬 필요가 있습니다(그리고 그것이 올바른 열에 있는지 확인하십시오).
awk
이러한 변형을 처리하고 올바르게 계산되는 출력을 생성할 수 있을 만큼 유연한 정규식을 만들려면 어떻게 해야 합니까 ?
답변1
여기서는 유연성, 가독성, 이식성을 사용 하겠습니다 Perl
. 복잡한 정규식은 사용하지 않습니다.KISS
(...저는 튜브 하나만 사용합니다 git
.)
패턴 중 하나가 있든 없든 어떤 경우에도 작동합니다. 그렇지 않으면 전혀 일치하지 않는 줄을 건너뜁니다.
$ 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열 구조입니다. 첫 번째 열은 삽입 횟수, 두 번째 열은 삭제 횟수, 마지막 열은 파일 이름입니다.
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
답변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
여기서 중요한 점은 삽입에 사용되는 그룹은 ?
그 뒤에 선택사항이며 캡처링 그룹은 일치 여부에 관계없이 왼쪽에서 오른쪽으로 번호가 매겨진다는 것입니다. 또한 세 가지 가능한 입력 형식이 모두 일치하도록 약간의 퍼지를 수행합니다. 물론 및 에 /, (\d+) insertion/
대해 두 개의 개별 일치 항목을 실행할 수도 있습니다./, (\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]