Bash / Awk脚本,用于根据搜索多个外部文件将列附加到单个文件

时间:2014-05-14 19:05:48

标签: bash awk lookup

我正在尝试编写一个将两个文件作为输入的脚本:

1)带注释的制表符分隔文件(" inFile")和
2)一个可变长度的文件,包含其他带注释的制表符分隔文件(相同的格式),每个文件用set_ids进行搜索...

file1  set1
file2  set2
file3  set3

我想输出inFile,但是附加了一些列,表明在每个要搜索的集合中是否找到了每行file_A。

这是我目前的代码

#!/bin/bash

inFile=$1
inSets=$2

set_filter () {
   set_name=$3
   awk -F"\t" ' BEGIN {OFS="\t"};
      {
         FNR == NR
            {
               idx=($1"."$2"."$3)
               keys[$idx]=$set_name
               next
            }
         {
            idx=($1"."$2"."$3)
            print $0, keys[$idx]
         }
      } ' $2 $1
   }

IFS=$'\n'
for line in $(cat $inSets); do

   set_file=$(echo $line | cut -f 1)
   set_id=$(echo $line | cut -f 2)

   ??? set_filter $inFile $set_file $set_id

done

我的基本想法是定义一个函数,该函数将执行单个文件的查找,并在循环中使用它来搜索所有要搜索的文件,并在每次迭代时添加一列。然而,我在循环方面遇到了麻烦,希望有人能指出我正确的方向。谢谢!

修改

带注释的文件看起来像

# inFile:
day  start  stop
1    100    102
1    300    350
2    100    200
3    200    400

所以我正在寻找实例(行),其中同一天.start.stop出现在被搜索的其中一个集合中。如果set1是:

day  start  stop
1    100    102
1    700    750
2    800    900
3    900    950

和set 2是:

day  start  stop
3    200    400
1    100    102
2    800    880
1    300    350

然后输出应该如下:

day  start  stop
1    100    102  set1  set2
1    300    350        set2 
2    100    200
3    200    400        set2

2 个答案:

答案 0 :(得分:1)

以下是使用awk的一种方式:

awk '
FILENAME != "infile" {
    line[FILENAME,$0] = FILENAME
    next
}
FNR > 1 {
    printf "%s", $0
    for (x in line) {
        split (x, t, SUBSEP)
        if (t[2] == $0) {
            sep = FS
            printf "%s%s", sep, line[x]
        }
    }
    print "";
    next
}1' set1 set2 infile 
day  start  stop
1    100    102 set2 set1 
1    300    350 set2 
2    100    200 
3    200    400 set2 

您可以继续添加套装,以确保您的infile在最后。

答案 1 :(得分:0)

这是另一个全部的答案。创建以下可执行awk文件:

#!/usr/bin/awk -f

BEGIN {DELIM=","; OFS="\t"} # DELIM should just be different than FS/data

# reformat input, set up some arrays
NR==FNR {
    line = $1 OFS $2 OFS $3   # replace with $0 if first file is tab delimited  
    if(FNR==1) header=line
    else { a[$2$3]=line; order[FNR-1]=$2$3; cnt++ }
    next
}

FILENAME!=last_filename { f[FILENAME]=++fcnt; last_filename=FILENAME }

$2$3 in a { a[$2$3]=a[$2$3] DELIM FILENAME }

# loop over lines in input file, adjusting formatting of lines in a[] with f[]  
END {
    print header
    for(i=1;i<=cnt;i++) { 
        split(a[order[i]], oarr, DELIM)
        printf( "%s", oarr[1] )
        k=2
        for(j=1;j<=fcnt;j++) {
            fname=oarr[k]
            if( f[fname]==j ) {o=fname; k++}
            else o=""
            printf( "%s%s", OFS, o )
        }
        print ""
    }
}

当放入名为awko的文件时,它可以像awko infile set*

一样运行
day     start   stop
1       100     102     set1    set2
1       300     350             set2
2       100     200             
3       200     400             set2

一般细分:

  • 将第一个文件存储在某些数组中,即变量
  • 创建一个以参数顺序测试的文件数组 - 用于对齐
  • 将所有匹配的文件名附加到a[]
  • 中的匹配行
  • 最后,按顺序打印a[]中的每一行,重新格式化以匹配匹配

存在line变量,因为问题中的数据在翻译中丢失了标签。