将毫秒转换为天的Bash脚本:小时:分钟:秒:毫秒

时间:2014-02-01 23:39:34

标签: bash awk

我编写了以下bash脚本将毫秒转换为Days:Hours:Minutes:Seconds:使日志文件更具可读性的毫秒:

    #!/bin/bash
    ### Constants ###
    CON_DAYS=.0000000115741
    CON_HOURS=.000000277778
    CON_MINUTES=.000066667
    CON_SECONDS=.001

    ### Variables ###
    INPUT="$1"

    cat $INPUT | awk -v CON_HOURS=$CON_HOURS -v CON_MINUTES=$CON_MINUTES -v CON_SECONDS=$CON_SECONDS -v CON_DAYS=$CON_DAYS '
        { $1=substr($0,0,10) }
        { MILLISECONDS = $1 }
        { DAYS = int(MILLISECONDS * CON_DAYS) }
        { MILLISECONDS = MILLISECONDS - int( DAYS / CON_DAYS ) }
        { HOURS = int(MILLISECONDS * CON_HOURS) }
        { MILLISECONDS = MILLISECONDS - int(HOURS / CON_HOURS) }
        { MINUTES = int(MILLISECONDS * CON_MINUTES) }
        { MILLISECONDS = MILLISECONDS - int(MINUTES / CON_MINUTES) }
        { SECONDS = int(MILLISECONDS * CON_SECONDS) }
        { MILLISECONDS = MILLISECONDS - int( SECONDS / CON_SECONDS ) }
        { $1 = DAYS":"HOURS":"MINUTES":"SECONDS":"MILLISECONDS"ms" }
        {print}'
    exit

输入文件部分:

1882224617mS ATMChannel: [1] CMLinkLayer Rx: 'DialDigits' (ls)
1882224617mS ATMIO:      [1] TONE DIAL (11 digits)
1882224617mS ATMChannel: [1] StateChange Connected->ToneDialing

有几行输出显示它无法正常工作:

22:19:224:14:186ms ATMChannel: [1] CMLinkLayer Rx: 'DialDigits' (ls)
22:19:224:14:186ms ATMIO: [1] TONE DIAL (11 digits)
22:19:224:14:186ms ATMChannel: [1] StateChange Connected->ToneDialing

经过几个小时的故障排除后,我无法找到错误。任何帮助将不胜感激。

3 个答案:

答案 0 :(得分:4)

分为毫秒和秒,使用GNU日期,您应该更容易获得结果

#!/bin/bash

INPUT="$1"

while read t rest
do
  ms=$(echo $t|sed -r "s/.*(.....)$/\1/")  # get Milliseconds  617mS
  se=$(echo $t|sed -r "s/(.....)$//")      # get seconds  1882224
  days=$(echo $se / 3600 / 24 |bc)

  d="$days:$(date -d "1970-01-01 $se seconds" +%H:%M:%S):$ms"
  echo "$d $rest"
done < $INPUT

答案 1 :(得分:3)

如果执行速度是一个问题,这将产生与接受的答案相同的输出,但它在我的机器上快了33倍(0.9s对30s,1000行文件):

#!/bin/bash
sed 's/\([[:digit:]]\{3\}\)mS/ \1mS/' "$1" | while read sec msec info; do
        for scale in 86400 3600 60 1; do
                num_scale=$((sec / scale))
                sec=$((sec - (scale * num_scale)))
                echo -n "$num_scale:"
        done
        echo "$msec $info"
done

效率来自以下方面:

  1. 在一个sed进程中完成将秒与毫秒分开,为while循环提供信息。
  2. 解析秒数,毫秒数和日志文本,每行read一次。
  3. 主循环内没有管道或子流程。
  4. 输出天数,小时数等只是通过简单的数学运算完成的,不需要通过date命令的解析器,格式化程序等。
  5. 虽然它没有标记在你的问题中,但默认情况下大多数UNIX上都安装了perl,非常适合这类任务,即使是快速而肮脏的风格,它也是速度的又一步(使用相同文件的0.05s;比我上面的BASH快18倍,比接受的答案快600倍):

    #!/usr/bin/perl
    @scales = (86400, 3600, 60, 1);
    while (<>) {
            ($sec, $msec, $info) = /^(\d+)(\d{3}mS)(.+)$/;
            foreach $scale (@scales) {
                    $num_scale = sprintf("%0d", $sec / $scale);
                    $sec -= $scale * $num_scale;
                    print "$num_scale:";
            }
            print "$msec$info\n";
    }
    

    执行时间测试和输出验证:

    $ for script in accepted.bash iscfrc.bash iscfrc.pl; do echo -n $script:; time ./$script log_1000.txt >$script.output; echo; done
    accepted.bash:
    real    0m30.257s
    user    0m4.040s
    sys     0m8.089s
    
    iscfrc.bash:
    real    0m0.881s
    user    0m0.672s
    sys     0m0.200s
    
    iscfrc.pl:
    real    0m0.052s
    user    0m0.040s
    sys     0m0.012s
    
    $ md5sum *.output
    e3a05f4f88a9d912f4ba92112dfbf709  accepted.bash.output
    e3a05f4f88a9d912f4ba92112dfbf709  iscfrc.bash.output
    e3a05f4f88a9d912f4ba92112dfbf709  iscfrc.pl.output
    
    $ tail -n3 *.output
    ==> accepted.bash.output <==
    21:18:50:24:617mS ATMIO:      [1] TONE DIAL (11 digits)
    21:18:50:24:617mS ATMChannel: [1] StateChange Connected->ToneDialing
    21:18:50:24:617mS ATMChannel: [1] CMLinkLayer Rx: 'DialDigits' (ls)
    
    ==> iscfrc.bash.output <==
    21:18:50:24:617mS ATMIO:      [1] TONE DIAL (11 digits)
    21:18:50:24:617mS ATMChannel: [1] StateChange Connected->ToneDialing
    21:18:50:24:617mS ATMChannel: [1] CMLinkLayer Rx: 'DialDigits' (ls)
    
    ==> iscfrc.pl.output <==
    21:18:50:24:617mS ATMIO:      [1] TONE DIAL (11 digits)
    21:18:50:24:617mS ATMChannel: [1] StateChange Connected->ToneDialing
    21:18:50:24:617mS ATMChannel: [1] CMLinkLayer Rx: 'DialDigits' (ls)
    

答案 2 :(得分:1)

不会使用(除非您在脚本中执行了所有操作)。

尝试类似

的内容
#!/bin/bash

INPUT="$1"
while IFS= read -r line; do
  [[ $line =~ ^[0-9]+ ]] && days=$(echo "${BASH_REMATCH[0]} / (1000 * 60 * 60 * 24)" | bc -l)
  [[ $days =~ '.'[0-9]+ ]] && hours=$(echo "${BASH_REMATCH[0]} * 24" | bc -l)
  [[ $hours =~ '.'[0-9]+ ]] && minutes=$(echo "${BASH_REMATCH[0]} * 60" | bc -l)
  [[ $minutes =~ '.'[0-9]+ ]] && seconds=$(echo "${BASH_REMATCH[0]} * 60" | bc -l)
  [[ $seconds =~ '.'[0-9]+ ]] && ms=$(echo "${BASH_REMATCH[0]} * 1000" | bc)
  [[ $line =~ 'mS'(.*) ]] && line="${BASH_REMATCH[1]}"
  printf "%d:%d:%d:%d:%d" "$days", "$hours", "$minutes", "$seconds", "$ms" 2>/dev/null
  printf "$line\n"
done < "$INPUT"

哪个产生

21:18:50:24:616 ATMChannel: [1] CMLinkLayer Rx: 'DialDigits' (ls)
21:18:50:24:616 ATMIO:      [1] TONE DIAL (11 digits)
21:18:50:24:616 ATMChannel: [1] StateChange Connected->ToneDialing