여러 파일의 특정 문자열 다음에 숫자를 grep하고 평균을 반환하는 정규식

여러 파일의 특정 문자열 다음에 숫자를 grep하고 평균을 반환하는 정규식

여러 파일에서 특정 문자열 뒤에 오는 모든 숫자의 평균을 반환하고 싶습니다.

10개의 파일(file1.txt,...,file10.txt)이 있습니다. 각 파일에는 다른 콘텐츠가 포함되어 있습니다.

Test1: Avg. length 24.01000, time: 0.579
Test2: Avg. length 22.02000, time: 0.879

다른 숫자로.

10개의 파일이 있다면 다음과 같을 것입니다.

파일 1.txt

Test1: Avg. length 24.01000, time: 0.679
Test2: Avg. length 22.01000, time: 0.479

파일 2.txt

Test1: Avg. length 27.01000, time: 0.279
Test2: Avg. length 24.01000, time: 0.779

파일 10.txt

내가 원하는 출력은 모든 파일에서 Test1과 Test2의 길이와 시간의 평균입니다.

Mean Test1: Avg. length (file1_Test1_length+...+file10_Test1_lenght)/10, time (file1_Test1_time+...+file_10_Test1_time)/10
Mean Test2: Avg. length (file1_Test2_length+...+file10_Test2_lenght)/10, time (file1_Test2_time+...+file_10_Test2_time)/10

Test1의 전체 출력을 grep하려면 다음을 실행합니다.

egrep -rh 'Test1: Avg. length.*' /home/timo/Documents

숫자만 grep하는 방법을 모르겠습니다. 나는 노력했다

egrep -rhP '(?<=length )\d+' /home/timo/Documents

그런데 오류가 발생해요

grep: conflicting matchers specified

누구든지 나를 도울 수 있다면 매우 감사하겠습니다!

답변1

다음 awk솔루션이 작동합니다.

awk -F'[ ,:]+' '$1~/^Test[12]/{l[$1]+=$4; t[$1]+=$6; n[$1]++;}
                END{if (n["Test1"]) {for (tst in l) printf("Mean %s: Avg. length %f, time: %f\n",tst,l[tst]/n[tst], t[tst]/n[tst]);} else {print "No input found"}}' file*.txt

Test1그러면 입력 파일에서 or로 시작하는 행 Test2과 합계 필드 4와 6(각각 "길이" 및 "시간") 을 구문 분석합니다 . 또한 데이터 카운터도 증가합니다 n. 마지막으로 평균값(데이터가 발견된 경우) 또는 오류 메시지를 인쇄합니다.

최소한 하나의 파일이 존재한다고 확신하는 경우 이를 다음과 같이 단순화할 수 있습니다.

awk -F'[ ,:]+' '$1~/^Test[12]/{l[$1]+=$4; t[$1]+=$6; n[$1]++;}
                END{for (tst in l) printf("Mean %s: Avg. length %f, time: %f\n",tst,l[tst]/n[tst], t[tst]/n[tst]);}' file*.txt

모든 파일이 별도의 하위 폴더에 있는 것으로 나타나므로 방법은 셸에 따라 다릅니다. 가장 간단한 경우에는 시도해 볼 수 있습니다.

awk -F'[ ,:]+' ' ... ' subdir*/file*.txt

답변2

GNU 사용 datamash:

$ grep '^Test.*Avg\. length.*time:' file*.txt | tr -d ',' | LC_ALL=C datamash -W -s -g 1 mean 4,6
Test1:  25.51   0.479
Test2:  23.01   0.629

먼저 표시하는 데 사용하는 행을 추출합니다 grep. Test줄의 시작 부분에 있는 텍스트를 일치시킨 다음 문자열 Avg. lengthtime:줄의 다른 부분을 일치시켜 이를 수행합니다 . 이 표현식을 수정하고 싶을 수도 있습니다(고유하게 일치하는지 모르겠습니다.오직우리가 관심 있는 행).

그런 다음 숫자 해석을 엉망으로 만들기 때문에 데이터에서 모든 쉼표를 제거했습니다. 나는 이것을 사용하여 tr.

grep+ 비트는 다음을 사용 tr하여 수행 할 수도 있습니다.sed

sed '/^Test.*Avg\. length.*time:/!d; s/,//g' file*.txt

그런 다음 GNU를 사용하여 datamash각 테스트의 평균 길이와 시간을 계산합니다. 나는 처음에 datamash공백을 구분 기호로 사용하라고 말했습니다 -W. + (또는 ) -s에서 오는 대로 데이터를 정렬하여 데이터를 전역적으로 효과적으로 그룹화합니다.greptrsed

그룹화는 각 행의 레이블을 그룹화 키로 -g 1정의 하여 TestN:수행 됩니다. 그런 다음 각 그룹에 대해 공백으로 구분된 4번째와 6번째 열의 평균을 계산합니다 mean 4,6. 여기서 .

유틸리티에서 소수점이 점 대신 쉼표를 사용할 것으로 예상할 수 있으므로 C(POSIX 로케일) 에 대한 로케일을 설정했습니다 .datamash

출력을 약간 장식하려면 다음 명령을 사용할 수 있습니다 awk.

sed '/^Test.*Avg\. length.*time:/!d; s/,//g' file*.txt |
LC_ALL=C datamash -W -s -g 1 mean 4,6 |
awk '{ printf "%s Avg. length: %s time: %s\n", $1,$2,$3 }'

이는 다음과 같이 출력될 수 있습니다.

Test1: Avg. length: 25.51 time: 0.479
Test2: Avg. length: 23.01 time: 0.629

관련 정보