파일의 6번째 행마다 5번째 행 값을 합산합니다.

파일의 6번째 행마다 5번째 행 값을 합산합니다.

다음과 같은 텍스트 블록이 포함된 txt 파일이 있습니다.

17-01-2023
Purchase AAA
Apple Pay John Doe
Full Payment
-11,34€
0,11€
30-01-2023
Purchase BBB
Mastercard Jane Doe
Installment
-23,90€
0,24€

따라서 날짜, 구매 유형, 결제 유형 및 이름, 결제 유형, 음수 값 및 할인이 순서대로 표시됩니다.

이는 수천 개의 항목이 포함된 파일에서 반복됩니다.

값의 합(이 경우 11,34 + 23,90)을 얻고 그 합을 양수로 만들고 싶습니다. 숫자 뒤에 유로 기호가 있고 내 로케일에서는 쉼표가 소수 구분 기호라는 것을 기억하세요.

sed, awk 등을 사용하여 터미널에서 이 작업을 어떻게 수행할 수 있나요?

답변1

awk를 사용할 수 있습니다. 숫자가 아닌 통화 기호 접두사(예: )가 있는 경우와 달리 €-23,90숫자 변환 중에 숫자가 아닌 접미사가 무시됩니다. 구현에 따라 로케일의 소수 구분 기호를 다르게 처리할 수 있습니다.

mawk 'NR%6 == 5 {sum -= $0} END {print sum}' file

존중 LC_NUMERIC/ LC_ALL요청에 따라POSIX 준수, GNU awk는 기본적으로 POSIX 사양에서 벗어나지만 로케일을 사용하도록 지시해야 합니다.

gawk --use-lc-numeric 'NR%6 == 5 {sum -= $0} END {print sum}' file

GNU Awk 사용자 가이드를 참조하세요:로케일은 변환에 영향을 미칩니다


예를 들어 de_DE.UTF-8 로케일을 사용하여 테스트합니다.

$ export LC_NUMERIC=de_DE.UTF-8
$ 
$ mawk 'NR%6 == 5 {sum -= $0} END {print sum}' yourfile
35,24
$ 
$ gawk --use-lc-numeric 'NR%6 == 5 {sum -= $0} END {print sum}' sum=x yourfile
35,24

Mac OS의 경우:

$ awk --version
awk version 20200816

$ export LC_NUMERIC=de_DE.UTF-8

$ awk 'NR%6 == 5 {sum -= $0} END {print sum}' yourfile
35,24

답변2

이것은 단지 재미를 위한 것입니다. GNU sed를 사용하여 빌드한다고 가정합니다 n~m.

$ sed -n '5~6{y/-,€/_.+/;p}' file | dc -e0 -f- -e_1\*p
35.24

(물론 필요한 경우 다른 sed 또는 tr을 추가하여 소수점을 원래 로케일로 다시 변환할 수 있습니다 ,).

답변3

거래 금액이 항상 레코드의 5번째 줄에 위치한다고 가정하면 레코드의 시작은 "DD-MM-YYYY" 형식의 날짜로 표시되며 이 패턴은 레코드의 시작 부분에만 발생할 수 있습니다. 다음 awk프로그램은 다음을 수행합니다.

awk -v dpt=$(locale decimal_point) '/^([[:digit:]]{2}-){2}[[:digit:]]{4}$/{line_of_rec=0}
     {if (++line_of_rec==5) { if (dpt==".") sub(/,/,"."); total-=$0 } }
     END{printf "Total payments: %.2f\n",total}' input.txt

작동 방식은 다음과 같습니다.

  • 명령의 결과를 프로그램에 locale decimal_point변수로 전달합니다 dpt. 이는 awk소수 구분 기호를 사용하여 입력 형식을 지정하는 설정에 있는 것처럼 보이지만 ,로케일은 사용되는 것으로 설정되어 숫자의 소수 부분이 누락되기 .때문에 관련이 있습니다 .awk
  • 패턴 인식을 통해 출발선을 기록하고(앞뒤 공백이 없다고 가정합니다!) 변수를 line_of_record0으로 설정합니다.
  • 각 행에 대해 line_of_record카운터를 늘립니다. 5에 도달하면 행 내용이 소수로 해석되도록 (필요한 경우) ,로 대체 하고 변수에서 행 내용을 빼서 양의 지불금 값이 합산되도록 합니다..awktotal
  • 줄 끝에서 합계가 인쇄됩니다.

이는 필요한 최소값보다 더 많은 코드이지만 빈 줄이 있으면 프로그램을 더욱 강력하게 만듭니다.분리된 기록(여전히 기록의 5행에 있는 거래 금액에 의존합니다.)

답변4

사용행복하다(이전 Perl_6)

유형 검사 없음:

~$ raku -ne 'state $sum1; $sum1 += $_.trans("," => ".").subst(/\€/) if ++$ % 6 == 5; END say $sum1;'  file

#OR 

raku -e 'my $sum1 += $_.trans("," => ".").subst(/\€/) if ++$ % 6 == 5 for lines; say $sum1;'  file

패스 유형 확인:

~$ raku -ne 'state Rat $sum1; $sum1 += $_.trans("," => ".").subst(/\€/) if ++$ % 6 == 5; END say $sum1;'  file

#OR

~$ raku -e 'my Rat $sum1 += $_.trans("," => ".").subst(/\€/) if ++$ % 6 == 5 for lines; say $sum1;'  file

간단히 말해서(첫 번째 예) Raku는 -ne명령줄에서 자동 인쇄가 아닌 플래그로 실행됩니다. 스칼라 변수 는 d $sum1입니다 . 이는 state플래그로 표시된 루프가 시작되기 -ne전에 인스턴스화 된다는 의미입니다. 두 번째 명령문에서 익명 증분 행 카운터 변수 모듈로를 6 ++$으로 나눈 값이 5이면 점에 쉼표가 추가 되고 유로 기호가 제거됩니다( 제거되지 않음) . 그런 다음 변수에 추가하십시오 . 루프의 끝 에서 .%trans,.subst+=$sumENDsay $sum1

입력 예:

17-01-2023
Purchase AAA
Apple Pay John Doe
Full Payment
-11,34€
0,11€
30-01-2023
Purchase BBB
Mastercard Jane Doe
Installment
-23,90€
0,24€

예제 출력:

-35.24

누적 합계의 경우 say변수를 누적하면 됩니다.

~$ raku -ne 'state $sum1; say $sum1 += $_.trans("," => ".").subst(/\€/) if ++$ % 6 == 5;'

예제 출력:

-11.34
-35.24

@AdminBee의 답변에서 영감을 받아 awk줄에 문자가 포함될 때만 줄 카운터를 늘리면 레코드 사이에 빈 줄을 허용할 수 있습니다..chars

~$ raku -ne 'state Rat $sum1; say $sum1 += $_.trans("," => ".").subst(/\€/) if .chars && ++$ % 6 == 5;'

&&출력 예(위에서 사용된 것과 동일 and):

-11.34
-35.24

OP의 예에 제공된 숫자는 RatRaku에서 기본적으로 이온 숫자로 입력됩니다(Raku에서 사용 가능한 다른 유형에는 Nums 및 Ints가 포함됨). RatRaku의 s(충분히 작다고 가정)는 일반적으로 반올림 오류가 발생하지 않으며 신속하게 분수로 변환됩니다. 예를 들어 END명령문을 다음과 같이 변경합니다.

~$ raku -ne 'state $sum1; $sum1 += $_.trans("," => ".").subst(/\€/) if ++$ % 6 == 5; END say $sum1.numerator, "/", $sum1.denominator;'

예제 출력:

-881/25

더 빠른 작업을 위해서는 say $sum1.nude를 반환하십시오 (-881 25).

https://docs.raku.org/언어/numerics.html#Rational
https://raku.org

관련 정보