如何通过变量在 bash 脚本中使用日期命令

如何通过变量在 bash 脚本中使用日期命令

我有一个包含特定日期的文件,我想将它们转换为 UTC 格式。所以我准备了一个小脚本

我收到以下错误:

date: option requires an argument -- 'd'
Try `date --help' for more information.
date: extra operand `16:16:53'

我的文件内容如下所示:

20191014161653042nmd
20191014161653052egc
20191004081901490egc
20191004081901493nex
20191004081901497nex
20191004081902531nex
20191004081902534ksd

我的代码如下所示:

for i in $(cut -f1 Firstfile)
do
echo "$i" > tmpfile
TIME=$(awk '{print substr($1,1,14)}' tmpfile | sed -re 's/^([0-9]{8})([0-9]{2})([0-9]{2})([0-9]{2})$/\1\\ \2:\3:\4/' | xargs date +@%s -d | xargs date -u +"%Y-%m-%dT%H:%M:%S" -d)
MSec=$(awk '{print substr($1,15,3)}' tmpfile)
Msg=$(awk '{print substr($1,18,3)}' tmpfile)
echo -e "$TIME.$MSec $Msg" >> ResultFile
done

当我单独使用该命令时,它工作正常并且得到了所需的结果。

awk '{print substr($1,1,14)}' tmpfile | sed -re 's/^([0-9]{8})([0-9]{2})([0-9]{2})([0-9]{2})$/\1\\ \2:\3:\4/' | xargs date +@%s -d | xargs date -u +"%Y-%m-%dT%H:%M:%S" -d

我在脚本中犯了什么错误?为什么当我在 for 循环中通过脚本传递它时它不起作用?

预期结果:

2019-10-14T20:16:52.042 nmd
2019-10-14T20:16:52.052 egc
2019-10-04T12:19:01.490 egc

等等

答案1

您的问题是您传递了太多数据来date使用xargs.另外,您不会在末尾传递额外的文本字符串以使其成为输出的一部分。

最好在awk脚本中完成整个操作。 GNUawkmawk都有进行基本时间戳操作的函数:

{
        YYYY    = substr($1, 1, 4)   # year
        mm      = substr($1, 5, 2)   # month
        dd      = substr($1, 7, 2)   # day
        HH      = substr($1, 9, 2)   # hour
        MM      = substr($1, 11, 2)  # minute
        SS      = substr($1, 13, 2)  # seconds
        sss     = substr($1, 15, 3)  # fractional seconds

        text    = substr($1, 18)     # the rest

        tm = mktime(sprintf("%s %s %s %s %s %s", YYYY, mm, dd, HH, MM, SS))
        printf("%s.%s %s\n", strftime("%Y-%m-%dT%H:%M:%S", tm, 1), sss, text)
}

这使用 挑选出输入时间戳的各个组成部分到各个变量中substr()。然后使用 计算 Unix 时间mktime()(假设输入时间位于本地时区),并使用 转换为适当格式的 (UTC) 时间戳字符串strftime()

请注意,秒的小数部分(sss在代码中)绝不是时间计算的一​​部分,而是按原样从输入传输到输出。

运行它:

$ awk -f script.awk file
2019-10-14T14:16:53.042 nmd
2019-10-14T14:16:53.052 egc
2019-10-04T06:19:01.490 egc
2019-10-04T06:19:01.493 nex
2019-10-04T06:19:01.497 nex
2019-10-04T06:19:02.531 nex
2019-10-04T06:19:02.534 ksd

mktime()请参阅手册strftime()中的文档awk

答案2

这是使用 sed 和 bash 的版本

 sed -re 's/^([0-9]{8})([0-9]{2})([0-9]{2})([0-9]{2})(([0-9]{3,}){0,1})([a-z].*)$/D="\1\ \2:\3:\4";M="\5";E="\7"/' /tmp/tmpfile  |\ 
  xargs -d'\n' -I=:= bash -c  '(=:=;echo $(date -u +"%Y-%m-%dT%H:%M:%S.$M" -d "TZ=\"America/New_York\" $D" )  $E)'

我只做了 1 sed 步骤以避免awk + sed
删除\sed 第二部分中的所有内容

我使用-Ixargs 选项来指定我将在哪里使用我的 arg ,{}例如find

为了避免使用两次日期,我使用日期选项TZ中的选项-d

这里我使用America/New_York作为输入的时区,您必须更改为正确的值。

相关内容