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 / 问题 / 688437
Accepted
Lucas Djeu
Lucas Djeu
Asked: 2022-01-30 02:39:27 +0800 CST2022-01-30 02:39:27 +0800 CST 2022-01-30 02:39:27 +0800 CST

文件头尾不同条件行的平均值

  • 772

编辑:为清晰起见对其进行了编辑,并使示例文件最小化且更具可重复性,以便于帮助。谢谢!

我有超过 1000 行的文件。每个文件都使用相同数量的行进行格式化。的格式有 3 个“标题行”,1000+ 行值(正负数,后有 6 个小数位),然后是 13 个“尾行”。行的格式可以在下面看到。在我的真实文件中,在某些行上,我想要不同的命令,例如从行中打印文本,对实际数据取平均值,复制文本的行和数据的平均值以及日期和时间的平均值。

这是一个大纲或各种长文件,其中包含关于每行目标的一些注释。

下面的大纲是一个 dbriavated 示例。包含数据的行(示例中的第 4-9 行)实际上是真实文件中的第 4-1436 行。那么大纲中的第 10 行就是实际文件中的第 1437 行。(希望这是有道理的)。数据线可以包含负数或正数,范围从 -100 到 +5000。

ABCDEFGH               # Line 1... print text into output file (same on across all files)
1                      # Line 2... Take average of values across all the files in this line
2048                   # Line 3... Take average of values across all the files in this line
8.123456               # Line 4... Take average of values across all the files in this line (could be positive or negative)
5.123456               # Line 5... Take average of values across all the files in this line (could be positive or negative)
5.654321               # Line 6... Take average of values across all the files in this line (could be positive or negative)
4.654321               # Line 7... Take average of values across all the files in this line (could be positive or negative)
9.654321               # Line 8... Take average of values across all the files in this line (could be positive or negative)
1.654321               # Line 9... Take average of values across all the files in this line (could be positive or negative)
90.00                  # Line 10... Check and make sure value in this line across print if same
Sprite                 # Line 11... check and see if text is same across all values and print if same
cats10                 # Line 12... check and see if text is same across all values and print if same
07/02/20               # Line 13... See below for explantion on next 3 lines
08:32                  # Line 14...
08:32                  # Line 15...
290.000000             # Line 16... average across all files on this line
10.750000              # Line 17... average across all files on this line
SCANS23                # Line 18... output should be SCANS "average of values"
INT_TIME57500          # Line 19... output should be INT_TIME "sum of values"
SITE northpole         # Line 20...Check if all lines are same if so print line
LONGITUDE -147.850037  # Line 21... Output should be LONGITUDE "average"
LATITUDE 64.859375     # Line 22... Output should be LONGITUDE "average"

第 13 行是数据的来源日期,第 14 行是开始时间和结束时间。可能使用某种日期到十进制命令..有没有办法取日期的平均值?如果一个数据是在 2020 年 7 月 2 日获取的,而另一个数据是在 2018 年 7 月 2 日获取的,那么输出可以是 19 年 7 月 2 日吗?时间的平均值也会被考虑在内。

我认为一些扩展的三元运算符可能是一条路径,但是使用这么多不同的情况根本不起作用。

awk -F: '
  FNR==1     { c++ };
  /^LATITUDE/    { a[FNR] += $6 };
  /^LONGITUDE/    { a[FNR] += $5 };
  /^SITE/    { a[FNR] += $4 };
  /^INT_TIME/    { a[FNR] += $3 };
  /^SCANS/    { a[FNR] += $2 };
  /^[+-]?([0-9]*[.])?[0-9]+$/ { a[FNR] += $1 };

  END {
    for (i in a) {
      printf (i==22 ? "LATITUDE%f": 
              i==21 ? "LONGITUDE%2.3f": 
              i==20 ? "SITE%2.3f": 
              i==19 ? "INT_TIME%2.3f": 
              i==18 ? "SCANS%2.3f": "%f") "\n", a[i] / c 
    }
  }' /home/test/test1.* > /home/average

假定所有示例文件都在其中,/home/test/aaaaaa-bbbb-cc10dddd-L1-2020070119*-01.std并希望“平均”文件输出/home/dir/aaaaaa-bbbb-cc10dddd-L1-2020070119-01.std格式为 /aaaaaa-bbbb-cc10-dddd-L1-"year""month""day""hour"-"elevation number “.std

输入文件于 2020 年 1 月 7 日 19 小时在海拔 1 处拍摄:

/home/dir/dir2/aaaaaa-bbbb-cc10dddd-L1-202007011918-01.std
/home/dir/dir2/aaaaaa-bbbb-cc10dddd-L1-202007011929-01.std
/home/dir/dir2/aaaaaa-bbbb-cc10dddd-L1-202007011941-01.std
/home/dir/dir2/aaaaaa-bbbb-cc10dddd-L1-202007011953-01.std

输出文件将是

/home/dir/aaaaaa-bbbb-cc10dddd-L1-2020070119-01.std

/home/dir/dir2/aaaaaa-bbbb-cc10dddd-L1-202007011918-01.std

ABCDEFGH
1
2048
-3.249389
-4.544701
5.822962
2.372011
-17.937092
20.000408
5.00
Sprite
cats10
07/01/20
19:18
19:18
290.000000
10.690000
SCANS23
INT_TIME57500
SITE northpole
LONGITUDE -147.850037
LATITUDE 64.859375

/home/dir/dir2/aaaaaa-bbbb-cc10dddd-L1-202007011929-01.std

ABCDEFGH
1
2048
-6.369022
-4.957337
-2.715081
1.766033
-20.002853
21.522350
5.00
Avantes
buoy10
07/01/20
19:29
19:29
290.000000
10.310000
SCANS23
INT_TIME57500
SITE giroof
LONGITUDE -147.850037
LATITUDE 64.859375

/home/dir/dir2/aaaaaa-bbbb-cc10dddd-L1-202007011926-01.std

ABCDEFGH
1
2048
2.961413
-14.236549
19.784035
2.711583
-18.305300
9.369226
5.00
Avantes
buoy10
07/02/20
19:26
19:26
290.000000
10.310000
SCANS23
INT_TIME57500
SITE giroof
LONGITUDE -147.850037
LATITUDE 64.859375
bash awk
  • 2 2 个回答
  • 139 Views

2 个回答

  • Voted
  1. Best Answer
    RudiC
    2022-01-31T01:43:39+08:002022-01-31T01:43:39+08:00

    这可能接近您需要的,将paste(希望不是太多)输入文件放入awk,关闭任何locale影响:

    paste file[1-3] | LC_ALL=C awk -v"LNCT=$(wc -l <file1)" '
    
    function avg(  sum)     {for (i=1; i<=NF; i++) sum += $i
                             return sum/NF
                            }
    
    function same()         {for (i=2; i<=NF; i++) if ($1 != $i) return 0
                             return 1
                            }
    
    NR == 1                 {print $1
                             next
                            }
    NR <= (LNCT-13) ||
    NR >= (LNCT-6)  &&
    NR <= (LNCT-5)          {print avg()
                             next
                            }
    
    NR >  (LNCT-13) &&
    NR <= (LNCT-10)         {print (same()?$1:"") 
                            }
    NR >= (LNCT-9) &&
    NR <= (LNCT-7)          {if (NR == (LNCT-9))    FMT = "%m/%d/%y"
                               else                 FMT = "%H:%M"
    
                             for (i=1; i<=NF; i++)  {CMD = "date +%s -d\"" $i"\""
                                                     CMD | getline  $i
                                                     close (CMD)
                                                    }
                             CMD = "date +" FMT " -d\"@" avg() "\""
                             CMD | getline ITEM
                             close (CMD)
                             print ITEM
                            }
    
                            {ITEM = $1
                             gsub (/[0-9]*/, "", ITEM)
                             if (gsub (/SCANS|INT_TIME|LONGITUDE|LATITUDE/, ""))    {print ITEM, avg()
                                                                                    }
                             if (gsub (/SITE/, ""))         print ITEM, (same()?$1:"") 
                            }
    '
    ABCDEFGH
    1
    2048
    -2.219
    -7.91286
    7.63064
    2.28321
    -18.7484
    16.964
    5.00
    
    
    07/01/20
    19:24
    19:24
    290
    10.4367
    SCANS 23
    INT_TIME 57500
    SITE 
    LONGITUDE -147.85
    LATITUDE 64.8594
    

    这有点笨拙,因为它通过行号检测“特殊处理”行,尤其是。日期/时间,但它似乎做了所要求的。我们需要预先计算行数并通过变量传递wc - l输出,awk假设所有文件都具有相同的长度。可能还有其他/更好的方法。对于日期/时间计算:对于每次发生的事件都运行一个外部命令,这非常耗费资源date,最重要的是,并非在所有操作系统版本上都可用。它适用于我的 linux 系统,但我愿意接受更好的想法。

    • 1
  2. Ed Morton
    2022-01-31T08:19:07+08:002022-01-31T08:19:07+08:00

    这可能是您正在寻找的,在日期平均计算中使用 GNU awk 作为时间函数并假设您的时区是 UTC 并且您的所有日期都是本世纪并且您没有任何空输入行:

    $ cat tst.sh
    #!/usr/bin/env bash
    
    paste "$@" |
    awk '
        BEGIN { FS="\t"; CONVFMT="%0.6f" }
        ( 1 <= NR) && (NR <=  1) { print chkSameStrnums() }
        ( 2 <= NR) && (NR <=  9) { print getTagAveNr() }
        (10 <= NR) && (NR <= 12) { print chkSameStrnums() }
        (13 <= NR) && (NR <= 13) { print getAveDate() }
        (14 <= NR) && (NR <= 15) { print getAveTime() }
        (16 <= NR) && (NR <= 17) { print getTagAveNr() }
        (18 <= NR) && (NR <= 18) { print getTagAveNr() }
        (19 <= NR) && (NR <= 19) { print getTagSumNr() }
        (20 <= NR) && (NR <= 20) { print chkSameStrnums() }
        (21 <= NR) && (NR <= 22) { print getTagAveNr() }
    
        function sumNrFlds(         i,sum,val) {
            for (i=1; i<=NF; i++) {
                val = $i
                sub(/^[^0-9-]+/,"",val)
                sum += val
            }
            return sum
        }
    
        function getTagAveNr(       tag) {
            tag = $1
            sub(/[0-9.-]+$/,"",tag)
            return tag (sumNrFlds() / NF)
        }
    
        function getTagSumNr(       tag) {
            tag = $1
            sub(/[0-9.-]+$/,"",tag)
            return tag sumNrFlds()
        }
    
        function getAveDate(        i,sum,d,secs) {
            for (i=1; i<=NF; i++) {
                split($i,d,"/")
                secs = mktime("20"d[3] " " d[1] " " d[2] " 12 00 00", 1)
                sum += secs
            }
            return strftime("%m/%d/%y",int(sum/NF))
        }
    
        function getAveTime(        i,sum,t,ave,hrs,mins) {
            for (i=1; i<=NF; i++) {
                split($i,t,":")
                mins = (t[1] * 60) + t[2]
                sum += mins
            }
            ave = sum/NF
            hrs = int(ave/60)
            mins = int(ave - (hrs * 60))
            return (hrs ":" mins)
        }
    
        function chkSameStrnums(    i,diff) {
            for (i=2; i<=NF; i++) {
                if ($i != $1) {
                    diff = 1
                    break
                }
            }
            return (diff ? "different" : $1)
        }
    '
    

    $ ./tst.sh file?
    ABCDEFGH
    1
    2048
    -2.218999
    -7.912862
    7.630639
    2.283209
    -18.748415
    16.963995
    5.00
    different
    different
    07/01/20
    19:24
    19:24
    290
    10.436667
    SCANS23
    INT_TIME172500
    different
    LONGITUDE -147.850037
    LATITUDE 64.859375
    

    如果日期在 2 次之间发生变化,时间计算会变得更有趣,但您通常无法在数据中表示它,所以我将其留作练习(提示:如果结束时间小于开始时间时间和你的间隔永远不能超过 24 小时,那么你知道你已经过了一天,所以可以将 24 小时添加到结束时间 - 如果间隔可以超过 24 小时,那么你就不走运了)。

    • 0

相关问题

  • 多行文件洗牌

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

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

  • `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