【问题标题】:awk split string with no delimiterawk 不带分隔符的拆分字符串
【发布时间】:2014-09-10 01:03:13
【问题描述】:

我有以下运行测试的结果/统计文件,我想使用 awk 进行分析:

$date     $time    $statname $traffic_rate $val1 $val2
20140909 132920326 stat1     30/sec        40    80
20140909 132950326 stat1     29/sec        60    20
20140909 133020326 stat1     28/sec        70    100
20140909 133050326 stat1     0/sec          0    0
20140909 133120326 stat1     0/sec          0    0
20140909 133150326 stat1     30/sec        90    50

$time 的格式为:HHMMSSmmm,统计信息每隔 30 秒生成一次。我需要对 $traffic_rate 值 >= '28/sec' 的每个连续统计数据的 $val$val2 值进行平均。忽略 traffic_rate = 28/sec 重复该过程,依此类推。

我想使用 bash 脚本,并认为 awk 将是分析列数据的好选择。为了将连续时间戳与 $traffic_rate >= 28/sec 进行比较,我需要将 $time 与 mktime 进行转换。但是,我不能拆分 $time,因为没有分隔符。有没有办法像 PHP 那样按字符数进行拆分?

示例输出如下:

test# $val   $val2
1      170/3 200/3
2      90/1  50/1

也就是说,每个连续的 >= 28/sec 是一个单独的测试结果,应该单独计算。

此外,任何其他分析这些类型模式的建议都将不胜感激。谢谢。

【问题讨论】:

  • 您还应该发布您尝试过的内容和预期的输出。
  • 添加了示例输出

标签: bash time awk split


【解决方案1】:

使用awk

awk -v OFS="\t" '
BEGIN { print "test#", "$val", "$val2" }
$4 == "0/sec" && count { 
    print ++id, val1/count, val2/count
    count = val1 = val2 = 0
} 
$4+0>=28 && NR>1 { 
    val1+=$5
    val2+=$6
    ++count
}
END { 
    print ++id, val1/count, val2/count
}' file
test#   $val      $val2
1       56.6667  66.6667
2       90       50

【讨论】:

    【解决方案2】:

    如果traffic_rate 是每 30 秒,您可以使用平均 val1 val2 的简短脚本完成您需要的操作:

    #!/bin/bash
    
    ## validate data file input
    [ -f "$1" ] || {
        printf "\nError: insufficient input. File '%s' not found.\n\n" "${0//\//}"
        exit 1
    }
    
    declare -i cnt=0                    # simple count variable
    
    printf "\n    val1    val2\n\n"     # print generic header
    
    ## read each line in file
    while read -r dt tm sn trf v1 v2 || [ -n "$dt" ]; do
    
        trf=${trf%/*}               # extract numeric traffic_rate
    
        if [ "$trf" = 30 ]; then    # if equal to 30
            v1a+=( $v1 )            # add values to v1 array and v2 array
            v2a+=( $v2 )
            ((cnt++))
        else
            v1s=0                   # reset v1 sum and v2 sum
            v2s=0
            for i in ${v1a[@]}; do v1s=$((v1s+i)); done # calculate v1 sum from v1 array
            for i in ${v2a[@]}; do v2s=$((v2s+i)); done # calculate v2 sum from v2 array
            if [ $v1s -gt 0 ] && [ $v2s -gt 0 ]; then   # if both greater than 0, output
                printf "  %6s  %6s\n" \
                $( echo "scale=2; $v1s/$cnt" | bc ) $( echo "scale=2; $v2s/$cnt" | bc )
            fi
            cnt=0
            unset v1a v2a
        fi
    
    done <"$1"
    
    ## output if array elements remain
    if [ ${#v1a[@]} -gt 0 ]; then
        v1s=0
        v2s=0
        for i in ${v1a[@]}; do v1s=$((v1s+i)); done
        for i in ${v2a[@]}; do v2s=$((v2s+i)); done
        if [ $v1s -gt 0 ] && [ $v2s -gt 0 ]; then
            printf "  %6s  %6s\n" \
            $( echo "scale=2; $v1s/$cnt" | bc ) $( echo "scale=2; $v2s/$cnt" | bc )
        fi
        cnt=0
        unset v1a v2a
    fi
    
    printf "\n"
    
    exit 0
    

    输出:

    $ bash avg30.sh dat/split.dat
    
        val1    val2
    
        56.66   66.66
        90.00   50.00
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-01
      • 1970-01-01
      • 2016-09-04
      • 2022-01-13
      相关资源
      最近更新 更多