使用 awk 处理 3 个文件

使用 awk 处理 3 个文件

考虑以下文件:

file1:

boo,8,1024
foo,7,2048

file2:

foo,0,24,154
noo,0,10,561

file3:

24,154,7,1024,0

我需要的是去文件1并检查是否$2==7;如果为 true,则采用$1和from$2$3文件1;现在我必须比较是否$1来自文件1等于$1文件2;如果是真的,我必须采取$3$4文件2不存在于文件1,那么我必须去文件3并检查是否$1来自文件3等于$3文件2,并$2文件3等于$4文件2;如果是,那么我必须检查是否$2来自文件1等于$3文件3,那么如果这个条件为真,我必须$3比较文件1$4来自文件3,如果$3文件1$4文件3

我尝试了以下脚本:

cat [file1] [file2] [file3] | 
awk -F, 
'{if(NF==3)
    {if($2==7){a[$1]=$1; b[$1]=$2; c[$1]=$3}
    }else
        {if(NF==4){if(a[$1]==$1){d[$3]=$3; e[$4]=$4}
                  }else
                        {if(NF==5){if(d[$1]==$1 && e[$2]==$2){print a[$1], b[$1], c[$1], d[$1]}}
                        }
                  }

  }'

期望的输出是:

foo,7,2048,24,154,1024

答案1

这对我有用:

awk -F, 'FNR==1{++f} \
  f==1 && $2==7 {a1[$1]++; a2[$2]=$3; o=$0} \
  f==2 && a1[$1] {o=o","$3","$4; a3[$3]=$4} \
  f==3 && a3[$1] && $2==a3[$1] && a2[$3] && $4<a2[$3] {print o}' \
file1 file2 file3

解释:

  • 第一行 ( FNR==1{++f}) 增加文件索引,以便稍后确定我们位于 1-3 的哪个文件中。
  • 文件1:如果$2等于7
    • a1使用$1索引、a2索引$2$3值填充数组
    • 写下o变量(输出)的前 3 个字段
  • 文件2:if$1等于(file2之前写在) $1file1a1
    • $3和附加$4到输出变量o
    • a3使用$3索引和$4值填充数组。
  • 文件3:如果:
    • $1等于 file2s $3(索引a3
    • $2等于 file2s $4( 的值a3
    • $3等于 file1s $2(索引a2
    • $4低于 file1s $3( 的值a2
  • 然后:
    • 打印 的值o

答案2

TXR解决方案:

@(repeat)
@id,@val0,@val1
@  (next)
@  (skip)
@id,@nil,@val2,@val3
@  (next)
@val2,@val3,@val0,@val4,@val5
@  (require (< (int-str val4) (int-str val1)))
@  (output)
@id,@val0,@val1,@val2,@val3,@val4
@  (end)
@(end)

跑步:

$ txr join.txr file1 file2 file3
foo,7,2048,24,154,1024

但精明的观察者会注意到,代码中的任何地方都没有指定 7,它只出现在输出中!这是因为代码实际上遍历了file1和中的所有记录打印满足匹配和约束的所有组合。样本数据中唯一带有val0being 的数据7

如果找到更多组合,则可能会被限制为7如下所示的组合:

$ txr -Dval0=7 join.txr file1 file2 file3
foo,7,2048,24,154,1024

# how about 6?
$ txr -Dval0=6 join.txr file1 file2 file3
# no output

TXR 模式提取语言在这里提供了一种大模式匹配,通过重复变量名、跨越多个文件、具有多行提取模式和非文本约束,以及嵌入的副作用(如输出等),隐式反向引用。

接受awk解决方案仔细翻译了TXR Lispawk:

(awk (:begin (set fs "," ofs ","))
     (:let o (a1 (hash :equal-based)) (a2 (hash)) (a3 (hash)))
     (t (mf [orf int-str identity])) ;; map those fields to integers, which can be
     ((and (= arg 1) (= [f 1] 7)) (inc [a1 [f 0] 0])
                                  (set [a2 [f 1]] [f 2])
                                  (set o rec))
     ((and (= arg 2) [a1 [f 0]]) (set o `@o,@[f 2],@[f 3]`)
                                 (set [a3 [f 2]] [f 3]))
     ((and (= arg 3)
           [a3 [f 0]]
           (= [f 1] [a3 [f 0]])
           [a2 [f 2]]
           (< [f 3] [a2 [f 2]])) (prn o)))

跑步:

$ txr awkit.tl file1 file2 file3
foo,7,2048,24,154

,1024输出中缺少所需部分;原来的“Awk Classic”有这种行为。

相关内容