1

我的 shell 技能有点生疏,但我想做的是取 2 个文件并根据匹配字段从另一个文件中“擦洗”一个。这是重要的部分,该行的其余部分可能会有所不同,但如果关键字段匹配,它将被删除。例如,我的文件是用竖线分隔的,第二个字段是关键字段。

File 1
------
acme|widg001|green|plant a|<timestamp>
acme|widg102|blue|plant b|<timestamp>
acme|widg002|yellow|plant a|<timestamp

File 2
------
acme|widg001|blue|plant a|<timestamp>
acme|widg701|blue|plant a|<timestamp>

当我从文件 1 中清理文件 2 时,我希望生成的文件包含的是

New File
------
acme|widg102|blue|plant b|<timestamp>
acme|widg002|yellow|plant a|<timestamp>

理想情况下,该解决方案将允许我指定超过 2 个文件,即从文件 1 中擦洗文件 2、3 和 4。

任何帮助都会很棒!

4

3 回答 3

1

这个 awk 一个班轮可以将多个文件作为参数工作:(file1 必须是最后一个)

 awk -F'|' 'ARGIND<ARGC-1{a[$2];next} !($2 in a)' fileN fileN-1..... file1

关键是ARGC and ARGINDawk的变量的使用。

用 3 个文件测试

kent$  head f*                                                  
==> f1 <==
acme|widg001|green|plant a|<timestamp>
acme|widg102|blue|plant b|<timestamp>
acme|widg002|yellow|plant a|<timestamp>

==> f2 <==
acme|widg001|blue|plant a|<timestamp>
acme|widg701|blue|plant a|<timestamp>

==> f3 <==
acme|widg102|blue|plant a|<timestamp>
acme|widg701|blue|plant a|<timestamp>

kent$  awk -F'|' 'ARGIND<ARGC-1{a[$2];next} !($2 in a)' f2 f3 f1
acme|widg002|yellow|plant a|<timestamp>
于 2013-08-07T14:08:51.280 回答
1

既然你要求使用 Bash,我决定只使用 Bash。根本没有外部程序。

IFS='|'
declare -A scrub

while read f1 f2 rest; do
    scrub[$f2]=0
done < file2.txt

while read f1 f2 rest; do
    if [ ! ${scrub[$f2]} ]; then
        echo "$f1|$f2|$rest"
    fi
done < file1.txt

这会首先缓存要清理的值,然后遍历第一个文件中的候选者,打印那些未清理的值。它不漂亮,但它是 Bash。

于 2013-08-07T13:59:40.087 回答
0

这看起来很接近

join --check-order -v 1 -t\| -j 2 \
     <(sort -t \| -k2 file1) 
     <(sort -t \| -k2 file2)

它打印

widg002|acme|yellow|plant a|<timestamp
widg102|acme|blue|plant b|<timestamp>

这看起来是正确的,除了事实

  • join由于期望输入的方式,该输出在键列上排序
  • 关键列被移到前面。如果你有标题栏--header会让这更清楚。

如果您坚持手动列排序,请尝试使用 FORMAT 规范,例如:

-o "$(echo 1.{1..5})"

哪个打印

acme|widg002|yellow|plant a|<timestamp
acme|widg102|blue|plant b|<timestamp>

man join并且man sort 是您的任何其他调整的朋友

于 2013-08-07T13:47:03.570 回答