
소스 파일:
- 제목은 다음으로 시작합니다.
H
- 예고편은 다음과 같이 시작됩니다.
T
- R로 시작하는 레코드
- 구분 기호는 다음과 같습니다.
|~^
입력 파일 샘플
R로 시작하는 입력 레코드에는 원본 소스 파일에 여러 필드가 있습니다. 여기서는 예제에서 5개 필드만 언급했습니다.
트레일러 레코드의 세 번째 열은 레코드 수이고 다섯 번째 열은 금액 열(레코드의 세 번째 열 또는 행)의 합계입니다.
분할 후 예고편은 개수 및 합계 열을 포함하는 다음 형식으로 새 파일에 추가되어야 합니다.
R로 시작하는 INPUT 레코드는 날짜 순서를 따르지 않습니다. 예를 들어 첫 번째 레코드는 2019-03-05로 기록되고 마지막 레코드도 같은 날짜입니다.
노트:
R로 시작하는 INPUT 레코드에는 여러 열의 날짜 필드가 포함되므로 세 번째 날짜 필드를 분할하는 것이 좋습니다.
또한 부탁드립니다날짜 필드의 타임스탬프 무시;날짜만 고려하고 날짜만을 기준으로 분할을 수행할 수 있습니다. 이상적으로는 세 번째 열에 있는 동일한 날짜의 모든 거래를 새 파일로 이동하고 합계와 개수가 추가된 헤더/트레일러로 이동해야 합니다. ****편집******** 내 질문은 여전히 동일하지만 금액 필드가 매우 큰 숫자인 경우(금액 필드 데이터 유형이 소수점이 최대 5점, 매번 (31,5)는 아니지만 소수점 이하 5자리의 금액이 있는 경우 최대 소수점 5자리까지 값이 적용됩니다.)
입력 파일:
H|~^20200425|~^abcd|~^sum
R|~^abc|~^2019-03-06T12:33:52.27|~^123562388.23456|~^2018-04-12T12:33:52.27|~^hhh
R|~^abc|~^2019-03-05T12:33:52.27|~^105603.042|~^2018-10-23T12:33:52.27|~^aus
R|~^abc|~^2019-03-05T12:33:52.27|~^2054.026|~^2018-10-24T12:33:52.27|~^usa
R|~^abc|~^2019-03-06T12:33:52.27|~^10.00|~^2018-09-11T12:33:52.27|~^virginia
R|~^abc|~^2019-03-05T12:33:52.27|~^30.00|~^2018-08-05T12:33:52.27|~^ddd
R|~^abc|~^2019-03-06T12:33:52.27|~^15.03|~^2018-10-23T12:33:52.27|~^jjj
R|~^abc|~^2019-03-06T12:33:52.27|~^10.04|~^2018-04-08T12:33:52.27|~^jj
R|~^abc|~^2019-03-05T12:33:52.27|~^20.00|~^2018-07-23T12:33:52.27|~^audg
T|~^20200425|~^8|~^xxx|~^123670130.37256
예상 출력
파일 1: 다음 이름으로 저장해야 합니다.20190305.txt
H|~^20200425|~^abcd|~^sum
R|~^abc|~^2019-03-05T12:33:52.27|~^105603.042|~^2018-10-23T12:33:52.27|~^aus
R|~^abc|~^2019-03-05T12:33:52.27|~^2054.026|~^2018-10-24T12:33:52.27|~^usa
R|~^abc|~^2019-03-05T12:33:52.27|~^30.00|~^2018-08-05T12:33:52.27|~^ddd
R|~^abc|~^2019-03-05T12:33:52.27|~^20.00|~^2018-07-23T12:33:52.27|~^audg
T|~^20200425|~^4|~^xxx|~^107707.068
파일 2: 다음 이름으로 저장해야 합니다.20190306.txt
H|~^20200425|~^abcd|~^sum
R|~^abc|~^2019-03-06T12:33:52.27|~^123562388.23456|~^2018-04-12T12:33:52.27|~^hhh
R|~^abc|~^2019-03-06T12:33:52.27|~^10.00|~^2018-09-11T12:33:52.27|~^virginia
R|~^abc|~^2019-03-06T12:33:52.27|~^15.03|~^2018-10-23T12:33:52.27|~^jjj
R|~^abc|~^2019-03-06T12:33:52.27|~^10.04|~^2018-04-08T12:33:52.27|~^jj
T|~^20200425|~^4|~^xxx|~^123562423.30456
답변1
마지막 편집으로 전체 질문을 변경했습니다.
이제 각 행에 대해 타임스탬프를 파일 이름으로 변환해야 합니다. 에서 까지
입니다 . 이것만으로도 꽤 많은 문자열 처리가 필요하며 이는 어떤 언어에서도 그리 빠르지 않습니다.2019-03-06T12:33:52.27
20190306
이 작은 부분은 awk에서 수행할 수 있습니다.
awk 'BEGIN{FS="\\|~\\^";OFS="|~^"}
$1=="R"{
t=gensub(/-/, "","g",$3)
s=gensub(/T.*/,"",1,t);
$3=s
}
1
' "file" >"file.adj"
그런 다음 타임스탬프 날짜(원래 문제)를 기준으로 파일이 여전히 분할됩니다. 필요한 최소 변경 목록은 다음과 같습니다.
- 입력의 각 줄을 지정된 파일($3으로 제공)에 복사합니다.
- 완료되면 (각 파일에 대해) 줄 수를 계산합니다.
- 그리고 필드의 값을 합산합니다
4
. - 모든 입력 행이 처리된 후 꼬리를 각 파일에 인쇄합니다.
전체 프로세스는 다음과 같이 awk에서 수행할 수 있습니다.
awk 'BEGIN { FS="\\|~\\^"; OFS="|~^" }
$1=="H"{ header=$0; hdr=$2 }
$1=="R"{
t=gensub(/-/, "","g",$3)
file=gensub(/T.*/,"",1,t);
sum[file]+=$4
if(count[file]==0){ print header >file }
count[file]++
print $0 >>file
}
END {
for( i in sum ){
print "T",hdr,count[i],"xxx",sum[i] >> i;
close(i)
}
}
' "file"
Perl을 사용하여 소스 파일을 100만 번 반복하면 전체 파일이 단 49.32초 만에 처리되었습니다. 최소 메모리 사용량(일일 합계 및 개수만 메모리에 유지하면 됨) 이것은 나에게 꽤 빠른 것 같습니다.
답변2
해결책 은 다음과 같습니다 awk
.
awk -F'\\|~\\^' '{
if($1=="H"){
head=$0
}
else if($1=="T"){
foot=$1"|~^"$2
foot4=$4
}
else{
date=$3;
sub("T.*","", date);
data[date][NR]=$0;
sum[date]+=$4;
num[date]++
}
}
END{
for(date in data){
file=date".txt";
gsub("-","",file);
print head > file;
for(line in data[date]){
print data[date][line] > file
}
printf "%s|~^%.3f|~^%s|~^%.3f\n", foot, num[date],
foot4, sum[date] > file
}
}' file
샘플 데이터를 실행하면 다음이 생성됩니다.
$ cat 20190305.txt
H|~^20200425|~^abcd|~^sum
R|~^abc|~^2019-03-05T12:33:52.27|~^105603.042|~^2018-10-23T12:33:52.27|~^aus
R|~^abc|~^2019-03-05T12:33:52.27|~^2054.026|~^2018-10-24T12:33:52.27|~^usa
R|~^abc|~^2019-03-05T12:33:52.27|~^30.00|~^2018-08-05T12:33:52.27|~^ddd
R|~^abc|~^2019-03-05T12:33:52.27|~^20.00|~^2018-07-23T12:33:52.27|~^audg
T|~^20200425|~^4.000|~^xxx|~^107707.068
$ cat 20190306.txt
H|~^20200425|~^abcd|~^sum
R|~^abc|~^2019-03-06T12:33:52.27|~^123562388.23456|~^2018-04-12T12:33:52.27|~^hhh
R|~^abc|~^2019-03-06T12:33:52.27|~^10.00|~^2018-09-11T12:33:52.27|~^virginia
R|~^abc|~^2019-03-06T12:33:52.27|~^15.03|~^2018-10-23T12:33:52.27|~^jjj
R|~^abc|~^2019-03-06T12:33:52.27|~^10.04|~^2018-04-08T12:33:52.27|~^jj
T|~^20200425|~^4.000|~^xxx|~^123562423.305
그리고 awk가 느리다고 생각하시는 것 같아서 대용량 파일로 테스트해봤습니다. 테스트 파일을 생성하기 위해 다음 명령을 실행했습니다.
perl -e '@d=<>; print $d[0]; $str=join("",@d[1..$#d-1]); print $str x 3500000; print $d[$#d]' file > bigFile
이렇게 하면 28000002줄을 포함하는 1.9G 파일이 생성됩니다. 여기서 첫 번째 줄은 원본 파일의 헤더이고, 마지막 줄은 원본 파일의 바닥글이며, 줄 사이에는 원본 파일 내용이 350만 번 반복됩니다. 그런 다음 이 파일에 대해 awk를 실행합니다(이 작업을 수행하려면 RAM이 충분하므로 최소 618M의 여유 RAM이 필요합니다).
$ time awk -F'\\|~\\^' '{ if($1=="H"){head=$0} else if($1=="T"){foot=$1"|~^"$2; foot4=$4;} else{date=$3; sub("T.*","", date);data[date][NR]=$0;sum[date]+=$4;num[date]++;} }END{for(date in data){file=date;gsub("-","",file); sub("T.*",".txt",file); print head > file; for(line in data[date]){print data[date][line] > file} printf "%s|~^%s|~^%s|~^%s\n", foot, num[date], foot4, sum[date] > file } }' bigFile
real 2m8.603s
user 2m0.610s
sys 0m6.795s
따라서 1.9G 데이터 28,000,002행을 2분 안에 처리할 수 있습니다. 이것은 꽤 빠르다(비록이삭의 해결책1m 30에서는 더 빠르고 메모리를 적게 사용하므로 UI에서 사용을 권장합니다. for
쉘 루프로는 결코 이렇게 빨리 얻을 수 없을 것이라고 장담할 수 있습니다 . 그 문제에 대해서는 R for 루프도 사용할 수 없습니다.