2013-08-07 63 views
1

我的外壳技能有点生疏,但我想要做的是从基于匹配字段的另一个文件获取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> 

当我擦洗文件2从文件1我希望得到的文件包含的内容是

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

理想的解决方案将允许我指定多于两个文件,即磨砂文件2,3 & 4从文件1.

任何援助将是伟大的!

+2

我不明白的操作。你的例子中的匹配字段是什么? – Jiminion

+0

他希望基于'widg ###'的文件1不是文件1,好像。 – SethMMorton

回答

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会使这个更清晰。

如果你坚持手工列顺序,尽量像一个格式规范:

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

它打印

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

man joinman sort是你的朋友,任何其他调整

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。

+0

+ +1,使用bash 4的关联数组比较优雅 – sehe

1

这AWK一个衬垫可以工作的多个文件作为参数:(文件1必须是最后一个)

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

的关键是AWK的ARGC and ARGIND变量的使用。

测试与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>