如何在linux中加速awk命令?

如何在linux中加速awk命令?,linux,awk,time,timezone,utc,Linux,Awk,Time,Timezone,Utc,我在linux中使用awk命令将utc转换为本地时间,但文件大小大于30GB,需要花费一个多小时 这是我的密码: awk -F"," '{cmd="date -d \"$(date -d \""$1"\")-4hours\" \"+%Y%m%d_%H\"";cmd | getline datum; close(cmd); print $0 ","datum""}' data.txt 我如何加快这个命令的速度,或者在linux中有没有简单的方法来完成这个转换 Here is the sample

我在linux中使用awk命令将utc转换为本地时间,但文件大小大于30GB,需要花费一个多小时

这是我的密码:

awk -F"," '{cmd="date -d \"$(date -d \""$1"\")-4hours\" \"+%Y%m%d_%H\"";cmd | getline datum; close(cmd); print $0 ","datum""}' data.txt
我如何加快这个命令的速度,或者在linux中有没有简单的方法来完成这个转换

Here is the sample of input:

utc,id
2018-03-31 16:00:49.425,4485
2018-04-1 17:01:19.425,30019
2018-05-31 18:01:49.425,15427
2018-08-20 19:01:55.425,17579
2018-09-2 20:02:31.425,23716
2018-10-15 21:03:34.425,24772

expected output:

utc,id,localtime
2018-03-31 16:00:49.425,4485,20180331_12
2018-04-1 17:01:19.425,30019,20180401_13
2018-05-31 18:01:49.425,15427,20180531_14
2018-08-20 19:01:55.425,17579,20180820_15
2018-09-2 20:02:31.425,23716,20180902_16
2018-10-15 21:03:34.425,24772,20181015_17

您最初的解决方案速度慢的原因是由于到目前为止的系统调用。使用awk处理的每个记录/行都会调用一个外部命令来执行日期转换。这样的外部调用需要加载到内存中并执行,其输出需要由awk处理。如果我们能够在awk本身中进行实际的日期转换,我们可以加快速度

一般性意见:当您将日期和时间从UTC转换为本地时区时,您必须考虑到1月1日与8月1日处于不同的时区。这是由于夏令时。下面的算法并不能解决这个问题,因为OP只是要求移动4小时,或者移动到他当前的时区。备注:gawk 4.1.2或更新版本的解决方案将考虑DST

下面,我将根据您使用的awk提供几种解决方案:

Gnu awk:gawk的各种扩展之一是时间函数。此问题的两个有用时间函数是mktime和strftime:

mktimedatespec,[utc标志]:将格式为YYYY MM DD hh MM ss的日期规范字符串datespec转换为Unix历元时间,即自1970 01 utc以来的总秒数。由于gawk-4.2.1,您可以使用utc标志指示datespec是否使用utc。在gawk-4.2.1之前,它假定为当地时区

strftimetformat,timestamp,[utc标志]:将历元时间戳转换为与date命令格式相同的格式化字符串。您可以使用utc标志指示返回的时间应为utc或本地时区

更多信息请访问

我们希望将字段1从UTC转换为本地时区。由于我们不知道字段1的格式,我们假设存在一个函数convert_timestr,该函数将str格式转换为mktime可以接受的YYYY MM DD hh MM ss格式:

gawk 4.1.2或更新版本:

在gawk 4.1.2之前:这里我们不能使用utc标志,因此我们强制awk在utc工作:

$ TZ=UTC awk 'BEGIN{FS=OFS=","}
             { # convert $1 into YYYY MM DD hh mm ss
               datestring=convert_time($1)
               # convert datestring (as UTC) into epoch 
               datum=mktime(datestring)
               # perform TZ correction
               datum-=4*3600;
               # convert epoch into string (local TZ)
               datum=strftime("\042%Y%m%d_%H\042",datum)
               # print and append
               print $0,datum
              }' data.txt
POSIX awk:如果您没有GNU awk,但有任何其他awk,则不能使用这些时间函数,因为它们是GNU awk特定的。但是,可以实施这些措施:

awk '

# Algorithm from "Astronomical Algorithms" By J.Meeus
function mktime_posix(datestring,    a,t) {
    split(datestring,a," ")
    if (a[1] < 1970) return -1
    if (a[2] <= 2) { a[1]--; a[2]+=12 }
    t=int(a[1]/100); t=2-t+int(t/4)
    t=int(365.25*a[1]) + int(30.6001*(a[2]+1)) + a[3] + t - 719593
    return t*86400 + a[4]*3600 + a[5]*60 + a[6]
}

function strftime_posix(epoch, JD,yyyy,mm,dd,HH,MM,SS,A,B,C,D,E ) {
    if (epoch < 0 ) return "0000 00 00 00 00 00.000000"
    JD=epoch; SS=JD%60; JD-=SS; JD/=60; MM=JD%60;
    JD-=MM; JD/=60; HH=JD%24; JD-=HH; JD/=24;
    JD+=2440588
    A=int((JD - 1867216.25)/(36524.25))
    A=JD+1+A-int(A/4)
    B=A+1524; C=int((B-122.1)/365.25); D=int(365.25*C); E=int((B-D)/30.6001)
    dd=B-D-int(30.6001*E)
    mm = E < 14 ? E-1 : E - 13
    yyyy=mm>2?C-4716:C-4715
    return sprintf("\042%0.4d-%0.2d-%0.2d %0.2d:%0.2d:%06.3f",yyyy,mm,dd,HH,MM,SS)
}

{ # convert $1 into YYYY MM DD hh mm ss
  datestring=convert_time($1)
  # convert datestring (as UTC) into epoch 
  datum=mktime_posix(datestring)
  # perform TZ correction
  datum-=4*3600;
  # convert epoch into string (local TZ)
  datum=strftime_posix(datum)
  # print and append
  print $0,datum
}' data.txt

您最初的解决方案速度慢的原因是由于到目前为止的系统调用。使用awk处理的每个记录/行都会调用一个外部命令来执行日期转换。这样的外部调用需要加载到内存中并执行,其输出需要由awk处理。如果我们能够在awk本身中进行实际的日期转换,我们可以加快速度

一般性意见:当您将日期和时间从UTC转换为本地时区时,您必须考虑到1月1日与8月1日处于不同的时区。这是由于夏令时。下面的算法并不能解决这个问题,因为OP只是要求移动4小时,或者移动到他当前的时区。备注:gawk 4.1.2或更新版本的解决方案将考虑DST

下面,我将根据您使用的awk提供几种解决方案:

Gnu awk:gawk的各种扩展之一是时间函数。此问题的两个有用时间函数是mktime和strftime:

mktimedatespec,[utc标志]:将格式为YYYY MM DD hh MM ss的日期规范字符串datespec转换为Unix历元时间,即自1970 01 utc以来的总秒数。由于gawk-4.2.1,您可以使用utc标志指示datespec是否使用utc。在gawk-4.2.1之前,它假定为当地时区

strftimetformat,timestamp,[utc标志]:将历元时间戳转换为与date命令格式相同的格式化字符串。您可以使用utc标志指示返回的时间应为utc或本地时区

更多信息请访问

我们希望将字段1从UTC转换为本地时区。由于我们不知道字段1的格式,我们假设存在一个函数convert_timestr,该函数将str格式转换为mktime可以接受的YYYY MM DD hh MM ss格式:

gawk 4.1.2或更新版本:

在gawk 4.1.2之前:这里我们不能使用utc标志,因此我们强制awk在utc工作:

$ TZ=UTC awk 'BEGIN{FS=OFS=","}
             { # convert $1 into YYYY MM DD hh mm ss
               datestring=convert_time($1)
               # convert datestring (as UTC) into epoch 
               datum=mktime(datestring)
               # perform TZ correction
               datum-=4*3600;
               # convert epoch into string (local TZ)
               datum=strftime("\042%Y%m%d_%H\042",datum)
               # print and append
               print $0,datum
              }' data.txt
POSIX awk:如果您没有GNU awk,但有任何其他awk,则不能使用这些时间函数,因为它们是GNU awk特定的。但是,可以实施这些措施:

awk '

# Algorithm from "Astronomical Algorithms" By J.Meeus
function mktime_posix(datestring,    a,t) {
    split(datestring,a," ")
    if (a[1] < 1970) return -1
    if (a[2] <= 2) { a[1]--; a[2]+=12 }
    t=int(a[1]/100); t=2-t+int(t/4)
    t=int(365.25*a[1]) + int(30.6001*(a[2]+1)) + a[3] + t - 719593
    return t*86400 + a[4]*3600 + a[5]*60 + a[6]
}

function strftime_posix(epoch, JD,yyyy,mm,dd,HH,MM,SS,A,B,C,D,E ) {
    if (epoch < 0 ) return "0000 00 00 00 00 00.000000"
    JD=epoch; SS=JD%60; JD-=SS; JD/=60; MM=JD%60;
    JD-=MM; JD/=60; HH=JD%24; JD-=HH; JD/=24;
    JD+=2440588
    A=int((JD - 1867216.25)/(36524.25))
    A=JD+1+A-int(A/4)
    B=A+1524; C=int((B-122.1)/365.25); D=int(365.25*C); E=int((B-D)/30.6001)
    dd=B-D-int(30.6001*E)
    mm = E < 14 ? E-1 : E - 13
    yyyy=mm>2?C-4716:C-4715
    return sprintf("\042%0.4d-%0.2d-%0.2d %0.2d:%0.2d:%06.3f",yyyy,mm,dd,HH,MM,SS)
}

{ # convert $1 into YYYY MM DD hh mm ss
  datestring=convert_time($1)
  # convert datestring (as UTC) into epoch 
  datum=mktime_posix(datestring)
  # perform TZ correction
  datum-=4*3600;
  # convert epoch into string (local TZ)
  datum=strftime_posix(datum)
  # print and append
  print $0,datum
}' data.txt

欢迎来到SO,请发布输入和预期输出的示例,然后让我们知道。字段1中的日期格式是什么样的?您的输入文件看起来如何?请发布输入和预期输出的示例,然后让我们知道。字段1中的日期格式如何?您的输入文件看起来如何
一个抬头:我的Debian拉伸,9.9提供GAWK 4.1.4,它显然不支持UTC标志:2无效作为MKTIME的参数数目。真的,这只是GWK 4.2和更高的一部分。@ IfAAK如果TE回答对你来说是完美的,你应该考虑接受它,就像这里解释的:只是一个提示:我的Debian Stretch,9.9提供GAWK 4.1.4,它显然不支持UTC标志:2对于MKTIMECTION是无效的参数。这只是GWK 4.2和更高的一部分。@ in FaAK如果TE回答对你来说是完美的,那么你应该考虑接受它,如这里所解释的: