AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 669665
Accepted
macxpat
macxpat
Asked: 2021-09-20 00:28:44 +0800 CST2021-09-20 00:28:44 +0800 CST 2021-09-20 00:28:44 +0800 CST

awk:将来自多个文件的列与跨多行数据的计算结合起来

  • 772

如何将多个文件中的选定列合并到一个文件中,并对相邻行数据进行一些计算?

这是一个示例:来自多个设备的多个数据文件,每个数据文件每个月报告多个传感器的数据。所以有一个文件/设备/月,我想要一个文件/传感器。

以下是一些示例数据和预期输出。

示例数据文件device0_202105.csv:

Date;Time;Timestamp;PM2_5;AQI;PM10;CO2
2021/05/01;00:00:49;1619827249;21.0;70;29.0;413
2021/05/01;00:10:49;1619827849;20.0;68;37.0;409
2021/05/01;00:20:49;1619828449;21.0;70;39.0;412
2021/05/03;08:10:39;1620029439;33.0;95;43.0;430
2021/05/03;08:20:39;1620030039;33.0;95;50.0;427
2021/05/03;08:30:39;1620030639;35.0;99;38.0;429
2021/05/03;08:40:39;1620031239;33.0;95;46.0;431
2021/05/03;18:10:39;1620065439;12.0;50;18.0;425
2021/05/03;18:20:39;1620066039;12.0;50;18.0;426

示例数据文件device0_202106.csv:

Date;Time;Timestamp;PM2_5;AQI;PM10;CO2
2021/06/01;08:19:16;1622535556;19.0;66;30.0;426
2021/06/01;08:29:16;1622536156;20.0;68;33.0;454
2021/06/01;08:39:16;1622536756;24.0;76;31.0;456
2021/06/01;20:49:16;1622580556;36.0;102;32.0;447

示例数据文件device1_202105.csv:

Date;Time;Timestamp;PM2_5;AQI;PM10;CO2
2021/05/03;11:14:59;1620040499;19.0;66;20.0;438
2021/05/03;11:15:09;1620040509;19.0;66;20.0;486
2021/05/03;11:15:19;1620040519;18.0;63;18.0;485

我想为整个可用数据周期(此处为 202105 和 202106)为每种类型的传感器(例如 CO2)创建一个文件,data-co2.csv使用上述数据看起来像这样:

Date;Time;Device 0;Device 1
2021/05/03;10:30;429.25;469.667
2021/06/01;10:30;475.333

每个设备的数据按列报告,每个数据点是某个时间间隔内的平均值。所以一行报告原始数据的时间间隔的平均值。

我最初只考虑每个工作日只有 2 个时间间隔:早上 8:00 到 13:00 的时间间隔(标记为 10:30)和下午的时间间隔从 13:00 到 18:00(标记为 15:30 )。

我计划运行一个awk脚本,该脚本由一个bash循环遍历设备和周期文件的脚本启动。这是我的脚本的开始。但是,我无法写入输出文件(我应该使用-inplace选项吗?)。我正在考虑更简单的路线:写入临时文件并稍后连接到输出文件。

#!/bin/bash
touch data-co2.csv
gawk -v device=0 -v sensor=18 -f read-data.awk device0_202105.csv data-co2.csv
#!/bin/gawk -f
BEGIN {
    FS  = "[;/:]";
    OFS = ";";
    day  = 1 ;
    sam = 0 ; nam = 0 ; spm = 0 ; npm = 0 ;
}
FNR==NR {
    if ( $1 ~ /20[0-9]{2}/ ) {
        if ( $3 != day ) {
            if ( nam != 0 ) a[date";10:30"] = sam / nam ;
            if ( npm != 0 ) a[date";15:30"] = spm / npm ;
            day = $3 ;
            sam = 0 ; nam = 0 ; spm = 0 ; npm = 0 ;
        }
        if ( strftime("%u", $7, 1) < 6) {
            if ( $4 >= 8 && $4 <= 12 ) {
                sam += $sensor ;
                ++nam ;
            }
            else if ( $4 >= 13 && $4 < 18 )  {
                spm += $sensor ;
                ++npm ;
            }
        }
        date = $1"/"$2"/"$3 ;
    }
    next ;
}
{
    if ( device == 0 ) {
       for ( i in a ) {
           print i, a[i] ;
       }
    }
    else {
       i = $1"/"$2"/"$3";10:30" ;
       j = $1"/"$2"/"$3";15:30" ;
       print $0, a[i] ;
       print $0, a[j] ;
    }
}

请注意,每台设备上报数据的时间不同,可能会因设备故障、网络问题等原因导致数据丢失。

根据评论进行编辑。

bash awk
  • 1 1 个回答
  • 149 Views

1 个回答

  • Voted
  1. Best Answer
    FelixJN
    2021-09-20T05:12:11+08:002021-09-20T05:12:11+08:00
    #setting ":" as FS allows taking hours as separate field
    BEGIN { FS="[:;]" ; OFS="\t" 
            #this gawk feature helps properly addressing the arrays in the end
            PROCINFO["sorted_in"] = "@ind_str_asc"
    }
    
    #get device ID from filename on every new file
    #get device IDs in array
    FNR==1 {devID=FILENAME ; sub(/_.*/,"",devID) ; devs[devID]=devID }
    
    #select time ranges, sum up values in time ranges and count occurences
    FNR>1 {
        if ($2 >= 8 && $2 <= 12) {
            vals[devID,$1,1030]=vals[devID,$1,1030]+$NF
            n[devID,$1,1030]++
            }
        else if ($2 >= 13 && $2 <= 17) {
            vals[devID,$1,1530]=vals[devID,$1,1530]+$NF
            n[devID,$1,1530]++
            }
    #get dates in array
        dates[$1]=$1
    }
        
    END {
        #needed for value selection
        times[1030]="10:30"
        times[1530]="15:30"
        #print headers
        printf("date\ttime")
        for (dev in devs) {printf("\t"dev)}
        printf("\n")
    
        
        #print values
        for (date in dates) {
        #get day of week from system date command
            cmd="date -d"date" +%w"
            cmd | getline dow
        #do not use Sat+Sun
            if ( dow != 0 && dow != 6 ) {
                for (time in times) {
                    printf(date"\t"times[time])
                    for (dev in devs) {
                        if ( !vals[dev,date,time] ) { printf("\tN/A") }
                        else { printf("\t"vals[dev,date,time]/n[dev,date,time]) }
                    }
                    printf("\n")
                }
            }
        }   
    }
    

    也许不是最优雅的,但它可以完成工作。请注意,数组遍历选项形式gawk是确保设备的列标题与值匹配的必要条件。

    从您的示例输入创建的名为 1_04、2_04 和 3_02 的示例输出表单文件添加了一些日期(5 月 1 日和 2 日是周末,未选择,添加了更多天数以测试“N/A”)和一些数字崩溃(以确保匹配号码和设备)。

    date    time    1   2   3
    2021/05/03  10:30   832 N/A 832
    2021/05/03  15:30   406 401 406
    2021/05/04  10:30   809 809 1009
    2021/05/04  15:30   N/A N/A N/A
    2021/05/06  10:30   N/A 832 N/A
    2021/05/06  15:30   N/A N/A N/A
    

    如您所见,它甚至会显示当整天或时间间隔没有为所有设备提供值时。但相应的日期必须在日志文件中。

    • 3

相关问题

  • 多行文件洗牌

  • 从文本文件传递变量的奇怪问题

  • 虽然行读取保持转义空间?

  • `tee` 和 `bash` 进程替换顺序

  • 运行一个非常慢的脚本直到它成功

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    模块 i915 可能缺少固件 /lib/firmware/i915/*

    • 3 个回答
  • Marko Smith

    无法获取 jessie backports 存储库

    • 4 个回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    user12345 无法获取 jessie backports 存储库 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl 为什么大多数 systemd 示例都包含 WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve