合并2个文件 - 列可选地来自file1和file2

时间:2014-11-15 08:48:26

标签: awk sed excel-2007

f1.txt

A, 77, 1, 2.0,  !P ,  F, - ,     
B,   77 , 4, 5, P,  P, - ,     
C, 88, 6,  7,   F,   P, -,

f2.txt

A, 77, 1, 2, P, F,  P,    
B, 77, 4, 5, F, P,  P,    
C, 88, 6, 7, F, P,  P,    
D, 99, 8, 9, P, P,  F, 

期望的输出

A, 77, 1, 2, P, not P(*), F, F, P, -,    
B, 77, 4, 5, F, P(*), P, P, P, -,    
C, 88, 6, 7, F, F, P, P, F, -,    
D, 99, 8, 9, P, -, P, -, P, -,

基本上,匹配两个文件中的4列,然后合并每个文件中的备用列:匹配4列,然后f2_column5然后f1_column5,如果不同则添加(*)(如果不可用)然后"-"

  1. 列数> 1000,f1.txt的#列和f2.txt的#列不一样
  2. 行数> 1000 {而f1.txtf2.txt
  3. 不一样
  4. (如果可能,代码可以扩展为超过2个文件输入(f1,f2);例如,f3.txt
  5. f3.txt:B,77,4,5,P,P, - , 和所需的输出(对于3个输入文件 - f1.txt,f2.txt,f3.txt)

    期望的输出

    A, 77, 1, 2, P, not P(*), -, -, F, F, P, -, -,    
    B, 77, 4, 5, F, P(*),  P(*), P, P, P, P, -, -,    
    C, 88, 6, 7, F, F, -,        P, P, -, F, -, -,   
    D, 99, 8, 9, P, -, -,        P, -, -, P, -, -,
    
                 |               |        |
                f2.5th          f2.6th   f2.7th
    

    =============================================== ========================================

    如果列数小于10,我可以使用以下

    awk 'FNR==NR {a[NR]=$1;
    b[NR]=$2;
    c[NR]=$3;
    d[NR]=$4;
    e[NR]=$5;
    f[NR]=$6;
    g[NR]=$7;
    next}
    {print $1,$2,$3,$4,$5,
    ( e[FNR]!="" ? e[FNR] : "-" ),
    $6,
    ( f[FNR]!="" ? f[FNR] : "-" ),
    $7,
    ( g[FNR]!="" ? g[FNR] : "-" ) }' f1.txt f2.txt
    

    但我假设f1.txtf2.txt的4列,而不是我想要的;我想看看它是否匹配。我不知道如何使用大量列以及检查(*)。

1 个答案:

答案 0 :(得分:1)

我认为你的问题存在过于宽泛的风险,但希望这可以作为一个起点。目前,输出不太正确,但调整代码以满足您的需求应该不会太难。

对于这个长度的脚本,我认为写一个awk脚本会更好。代码可以保存到文件中并使用awk -f script.awk f1 f2

运行
BEGIN { FS = "[[:space:]]*,[[:space:]]*" }
NR == FNR {
    k = $1 SUBSEP int($2) SUBSEP int($3) SUBSEP int($4)
    seen[k]=NF
    for (i=5; i<=NF; ++i) { 
        a[k,i] = $i 
    }
    next
}
{
    k = $1 SUBSEP int($2) SUBSEP int($3) SUBSEP int($4)
    seen[k]=seen[k]>NF?seen[k]:NF
    for (i=5; i<=NF; ++i) { 
        b[k,i] = $i
    }
}
END {
    for (i in seen) {
        n = split(i, c, SUBSEP)
        for (j=1; j<=n; ++j)
            printf "%s, ", c[j]
        for (k=5; k<seen[i]; ++k)
            printf "%s, %s,%s", b[i,k], a[i,k], (k<seen[i]-1?OFS:ORS)            
    }
}

说明:

  • 将字段分隔符设置为逗号,由任意数量的空格字符包围
  • NR==FNR(在第一个文件中)时:
    • 将数组键k设置为由特殊变量SUBSEP分隔的前四个字段组成的字符串。使用int()将数字转换为整数值
    • 数组seen会跟踪到目前为止的密钥。数组中的值设置为字段数,稍后在循环中使用
    • 遍历从5开始的所有字段,并设置数组a
    • 中字段的值
    • 跳至next记录,忽略其余任何说明
  • 在第二个文件中:
    • 以相同方式再次设置键k
    • 如果第二个文件的密钥字段数更多,请更新seen中的值(我不确定文件中的每一行是否具有相同数量的密钥?)
    • 将文件中的每个字段保存到数组b
  • 处理完所有记录后:
    • 循环浏览seen
    • 中的键
    • 拆分我们之前使用的分隔符SUBSEP上的键
    • split返回数组c
    • 中的元素数
    • 遍历每个元素并打印值
    • 从5开始循环到最大字段数,打印来自ab的备用值

需要做的事情:

  • 检查b[i,k]a[i,k]是否不同,以便添加(*)
  • !替换为not 这两件事只是在END块中添加额外逻辑的情况。