【问题标题】:How to merge two .txt files into one, matching each line by timestamp, using awk如何使用awk将两个.txt文件合并为一个,按时间戳匹配每一行
【发布时间】:2019-10-14 11:26:01
【问题描述】:

总结:

我目前有两个从我正在测试的调查系统导入的 .txt 文件。每个数据文件的第 1 列是“HHMMSS.SSSSSS”格式的时间戳。在文件 1 中,有第二列场强读数。在 file2 中有两列额外的位置信息。我正在尝试编写一个脚本,通过排列时间戳来匹配这些文件之间的数据点。问题是任何时间戳都不是完全相同的值。该脚本必须能够匹配数据点(每个 .txt 文件中的行),基于其在另一个文件中最接近的对应物的时间戳(即,文件 1 中的时间 125051.354948 应该“匹配”文件 2 中最近的时间戳,即 125051.112784)。

如果有更多 awk/sed/join/regex/Unix 知识的人能指出正确的方向,我将不胜感激。

我目前所拥有的:

(请注意,此处显示的确切语法对于此问题中附加的示例 .txt 文件可能没有意义,这些文件有更广泛的版本,其中包含更多用于测试脚本的列。)

我是 awk/Unix/shell 脚本的新手,所以如果其中一些试用解决方案不起作用或没有多大意义,请多多包涵。

我已经尝试过在此处发布的一些使用 join 解决堆栈溢出问题的解决方案,但它似乎不想正确排序或加入这些文件中的任何一个:

    ${
      join -o 1.1,2.2 -1 2 -2 1 <(sort -k 2 file1) <(sort -k 1 file2)     
      join -v 1 -o 1.1,1.2 -1 2 -2 1 <(sort -k 2 file1) <(sort -k 1 
    file2) 
    } | sort -k 1
  • 结果:仅输出与原始文件相似的版本2

我也尝试重新配置此处发布的现有 awk 解决方案:

    awk 'BEGIN {FS=OFS="\t"} NR==FNR {v[$3]=$2; next} {print $1, (v[$3] ? 
    v[$3] : 0)}' file1 file2 > file3


    awk 'BEGIN {FS=OFS="\t"} NR==FNR {v[$1]=$2; next} {print $1, (v[$1] ? 
    v[$1] : 0)}' file1 file2 > file3
  • 结果:这两个 awk 命令都会导致 file2 的输出 不包含来自 file1 的数据(或者看起来如此)。

    awk -F '
    FNR == NR {
        time[$3]
        next
    }
    {   for(i in time)
            if(index($3, i) == 1) {
                print
                next
    
            }
    }' file1 file2 > file3
    
  • 结果:不断返回有关“.”的语法错误。 “.txt”

我考虑将某种正则表达式或拆分命令集成到脚本中......但对如何进行感到困惑并且没有提出任何实质内容。

样本数据

    $ cat file1.txt

    125051.354948 058712.429

    125052.352475 058959.934

    125054.354322 058842.619

    125055.352671 058772.045

    125057.351794 058707.281

    125058.352678 058758.959


    $ cat file2.txt

    125050.105886 4413.34358 07629.87620

    125051.112784 4413.34369 07629.87606

    125052.100811 4413.34371 07629.87605

    125053.097826 4413.34373 07629.87603

    125054.107361 4413.34373 07629.87605

    125055.107038 4413.34375 07629.87604

    125056.093783 4413.34377 07629.87602

    125057.097928 4413.34378 07629.87603

    125058.098475 4413.34378 07629.87606

    125059.095787 4413.34376 07629.87602

预期结果:

(格式:Column1File1 Column1File2 Column2File1 Column2File2 Column3File2)

    $ cat file3.txt

    125051.354948 125051.112784 058712.429 4413.34358 07629.87620

    125052.352475 125052.100811 058959.934 4413.34371 07629.87605

    125054.354322 125054.107361 058842.619 4413.34373 07629.87605

    125055.352671 125055.107038 058772.045 4413.34375 07629.87604

    125057.351794 125057.097928 058707.281 4413.34378 07629.87603

    125058.352678 125058.098475 058758.959 4413.34378 07629.87606

如图所示,并非每个文件中的每个数据点都能找到匹配项。只有具有最接近时间戳的行对才会被写入新文件

如前所述,当前的解决方案导致 file3 完全空白,或仅包含来自两个文件之一的信息(但不是两者)

【问题讨论】:

    标签: bash shell unix awk command-line


    【解决方案1】:
    #!/bin/bash
    
    if [[ $# -lt 2 ]]; then
      echo "wrong args, it should be $0 file1 file2"
      exit 0
    fi
    
    # clear blanks, add an extra column 'm' to file1, merge file1, file2, sort
    { awk 'NF{print $0, "m"}' "$1" ; awk 'NF' "$2"; } | sort -nk1,1 | \
      \
      awk '# record lines and fields in to a
           {a[NR] = $0; a[NR,1] = $1; a[NR,2] = $2; a[NR,3] = $3}
           END{
             for(i=1; i<= NR; ++i){
    
               # 3rd filed of file1 is "m"
               if(a[i, 3] == "m"){
    
                 # get difference of column1 between current record ,previous record, next record
                 prevDiff = (i-1) in a && a[i-1,3] == "m" ? -1 : a[i,1] - a[i-1,1]
                 nextDiff = (i+1) in a && a[i+1,3] == "m" ? -1 : a[i+1,1] - a[i,1]
    
                 # compare differences, choose the close one and print.
                 if(prevDiff !=-1 && (nextVal == -1 || prevDiff < nextDiff))
                   print a[i,1], a[i-1, 1], a[i, 2], a[i-1, 2], a[i-1, 3]
                 else if(nextDiff !=-1 && (prevDiff == -1 || nextDiff < prevDiff))
                   print a[i,1], a[i+1, 1], a[i, 2], a[i+1, 2], a[i+1, 3]
                 else
                   print a[i]
               }
             }
           }'
    

    { awk 'NF{print $0, "m"}' "$1" ; awk 'NF' "$2"; } | sort -nk1,1 的输出是:

    125050.105886 4413.34358 07629.87620
    125051.112784 4413.34369 07629.87606
    125051.354948 058712.429 m
    125052.100811 4413.34371 07629.87605
    125052.352475 058959.934 m
    125053.097826 4413.34373 07629.87603
    125054.107361 4413.34373 07629.87605
    125054.354322 058842.619 m
    125055.107038 4413.34375 07629.87604
    125055.352671 058772.045 m
    125056.093783 4413.34377 07629.87602
    125057.097928 4413.34378 07629.87603
    125057.351794 058707.281 m
    125058.098475 4413.34378 07629.87606
    125058.352678 058758.959 m
    125059.095787 4413.34376 07629.87602
    

    【讨论】:

      【解决方案2】:

      请尝试以下方法:

      awk '
          # find the closest element in "a" to val and return the index
          function binsearch(a, val, len,
              low, high, mid) {
              if (val < a[1])
                  return 1
              if (val > a[len])
                  return len
      
              low = 1
              high = len
              while (low <= high) {
                  mid = int((low + high) / 2)
                  if (val < a[mid])
                      high = mid - 1
                  else if (val > a[mid])
                      low = mid + 1
                  else
                      return mid
              }
              return (val - a[low]) < (a[high] - val) ? high : low
          }
          NR == FNR {
              time[FNR] = $1
              position[FNR] = $2
              intensity[FNR] = $3
              len++
              next
          }
          {
              i = binsearch(time, $1, len)
              print $1 " " time[i] " " $2 " " position[i] " " intensity[i]
          }
      ' file2.txt file1.txt
      

      结果:

      125051.354948 125051.112784 058712.429 4413.34369 07629.87606
      125052.352475 125052.100811 058959.934 4413.34371 07629.87605
      125054.354322 125054.107361 058842.619 4413.34373 07629.87605
      125055.352671 125055.107038 058772.045 4413.34375 07629.87604
      125057.351794 125057.097928 058707.281 4413.34378 07629.87603
      125058.352678 125058.098475 058758.959 4413.34378 07629.87606
      

      请注意,您预期结果中的第 4 和第 5 个值可能被错误地复制和粘贴。

      [工作原理]

      关键是 binsearch 函数,它在 数组并返回数组的索引。我不会提及 详细介绍该算法,因为它是一种常见的“二分搜索”技术。

      【讨论】:

        猜你喜欢
        • 2015-02-06
        • 1970-01-01
        • 1970-01-01
        • 2020-06-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多