7GB 크기의 파일이 있습니다. 이제 두 개의 날짜/시간이 있으며 awk를 사용하여 이 두 날짜/시간 사이의 시차를 얻고 싶습니다.
내 파일은 다음과 같습니다.
A B C D E
18/06/28 09:19:07 295 141536 18-06-28 09:17:47
18/06/28 09:20:07 268 1160 18-06-28 09:18:58
18/06/28 09:21:07 317 1454 18-06-28 09:19:47
18/06/28 09:22:07 275 1491 18-06-28 09:20:59
18/06/28 09:23:07 320 1870 18-06-28 09:21:07
18/06/28 09:24:07 310 1869 18-06-28 09:22:30
18/06/28 09:25:07 150 693 18-06-28 09:23:28
18/06/28 09:26:07 414 2227 18-06-28 09:24:34
(AB) - (E) 사이의 차이를 원합니다.
나는 이것을 시도했습니다 :
cat filename | awk -F " " '{print date -d ($1$2)-($5)}'
출력은 두 날짜/시간 간의 시차여야 합니다. 첫 번째 행의 차이는 1분 20초입니다.
답변1
GNU awk 사용:
gawk '
function dt2epoch(date, time, timestr) {
timestr = "20" substr(date,1,2) " " substr(date,4,2) " " substr(date,7,2) \
" " substr(time,1,2) " " substr(time,4,2) " " substr(time,7,2)
return mktime(timestr)
}
function epoch2hms(t) {
return strftime("%H:%M:%S", t, 1)
}
function abs(n) {return n<0 ? -1*n : n}
NR == 1 {next}
{ print epoch2hms(abs(dt2epoch($5,$6) - dt2epoch($1,$2))) }
' file
산출
00:01:20
00:01:09
00:01:20
00:01:08
00:02:00
00:01:37
00:01:39
00:01:33
Perl의 경우 나는 사용할 것입니다날짜 시간생태계:
perl -MDateTime::Format::Strptime -lane '
BEGIN {$f = DateTime::Format::Strptime->new(pattern => "%y-%m-%d %H:%M:%S")}
next if $. == 1;
$F[0] =~ s{/}{-}g;
$t1 = $f->parse_datetime("$F[0] $F[1]");
$t2 = $f->parse_datetime("$F[4] $F[5]");
$d = $t1->subtract_datetime($t2);
printf "%02d:%02d:%02d\n", $d->hours, $d->minutes, $d->seconds;
' file
비핵심 모듈이 필요하지 않은 더 빠른 버전의 Perl
perl -MTime::Piece -lane '
next if $. == 1;
$t1 = Time::Piece->strptime("$F[0] $F[1]", "%y/%m/%d %H:%M:%S");
$t2 = Time::Piece->strptime("$F[4] $F[5]", "%y-%m-%d %H:%M:%S");
$diff = gmtime(abs($t1->epoch - $t2->epoch));
print $diff->hms;
' file
또는 대체 출력:
$ perl -MTime::Piece -lane '
next if $. == 1;
$t1 = Time::Piece->strptime("$F[0] $F[1]", "%y/%m/%d %H:%M:%S");
$t2 = Time::Piece->strptime("$F[4] $F[5]", "%y-%m-%d %H:%M:%S");
print abs($t1 - $t2)->pretty;
' file
1 minutes, 20 seconds
1 minutes, 9 seconds
1 minutes, 20 seconds
1 minutes, 8 seconds
2 minutes, 0 seconds
1 minutes, 37 seconds
1 minutes, 39 seconds
1 minutes, 33 seconds
답변2
사용 bash
및 awk
조합:
$ awk 'NR>1 {print $1,$2,$5,$6}' input | while read d1 t1 d2 t2; do
i1=$(date -u -d "20$d1 $t1" +%s)
i2=$(date -u -d "20$d1 $t2" +%s)
date -d @"$((i1-i2))" +%M:%S;
done
01:20
01:09
01:20
01:08
02:00
01:37
01:39
01:33
답변3
벤치마킹: 샘플 데이터를 여러 번 반복했습니다.
$ wc -l file
131073 file
이제 일정은 다음과 같습니다.
$ time awk 'NR>1 {print $1,$2,$5,$6}' file |
while read d1 t1 d2 t2; do
i1=$(date -u -d "20$d1 $t1" +%s)
i2=$(date -u -d "20$d1 $t2" +%s)
date -d @"$((i1-i2))" +%M:%S
done > /dev/null
real 8m55.533s
user 5m46.956s
sys 1m33.726s
$ time perl -MDateTime::Format::Strptime -lane '
BEGIN {$f = DateTime::Format::Strptime->new(pattern => "%y-%m-%d %H:%M:%S")}
next if $. == 1;
$F[0] =~ s{/}{-}g;
$t1 = $f->parse_datetime("$F[0] $F[1]");
$t2 = $f->parse_datetime("$F[4] $F[5]");
$d = $t1->subtract_datetime($t2);printf "%02d:%02d:%02d\n", $d->hours, $d->minutes, $d->seconds;
' file > /dev/null
real 0m37.684s
user 0m33.168s
sys 0m0.058s
$ time gawk '
function dt2epoch(date, time, timestr) {
timestr = "20" substr(date,1,2) " " substr(date,4,2) " " substr(date,7,2) \
" " substr(time,1,2) " " substr(time,4,2) " " substr(time,7,2)
return mktime(timestr)
}
function epoch2hms(t) {
return strftime("%H:%M:%S", t, 1)
}
function abs(n) {return n<0 ? -1*n : n}
NR == 1 {next}
{ print epoch2hms(abs(dt2epoch($5,$6) - dt2epoch($1,$2))) }
' file > /dev/null
real 0m1.074s
user 0m0.610s
sys 0m0.366s
시간 함수가 내장된 GNU awk가 모든 문자열 조작에도 불구하고 확실한 승자입니다.
업데이트: 새로운 Perl 구현. 여전히 gawk보다 느리지만 기능은 풍부하지만 무게가 무거운 DateTime 모듈을 사용하는 버전보다 훨씬 앞서 있습니다.
$ time perl -MTime::Piece -lane '
next if $. == 1;
$t1 = Time::Piece->strptime("$F[0] $F[1]", "%y/%m/%d %H:%M:%S");
$t2 = Time::Piece->strptime("$F[4] $F[5]", "%y-%m-%d %H:%M:%S");
$diff = gmtime(abs($t1->epoch - $t2->epoch));
print $diff->hms;
' file > /dev/null
real 0m2.631s
user 0m2.231s
sys 0m0.170s