如何找到两个文件中两个字段的值之间的差异,并且只有在使用shell时存在差异> 10时才打印

时间:2014-04-07 10:06:27

标签: shell sed awk grep

假设我有两个文件a.txt和b.txt。 a.txt和b.txt的内容如下:

A.TXT:

abc|def|ghi|jfkdh|dfgj|hbkjdsf|ndf|10|0|cjhk|00|098r|908re|
dfbk|sgvfd|ZD|zdf|2df|3w43f|ZZewd|11|19|fdgvdf|xz00|00|00

b.txt:

abc|def|ghi|jfkdh|dfgj|hbkjdsf|ndf|11|0|cjhk|00|098r|908re|
dfbk|sgvfd|ZD|zdf|2df|3w43f|ZZewd|22|18|fdgvdf|xz00|00|00

所以我们假设这些文件的各个字段用“|”分隔并且可以有任意数量的行。另外,假设两者都是已排序的文件,因此我们可以匹配两个文件之间的确切行。现在,我想找到8和8之间的区别。每个行的9个分别进行比较,如果它们的差异大于10,则打印行,否则从文件中删除行。

即,在给定的例子中,我将减去| 10-11 | (各自的字段编号8是来自a.txt和b.txt的1(绝对值))并且类似地对于字段编号。 9(0-0)为0,两者的差值都<10,所以我们从文件中删除这一行。

对于第二行,差异是(11-22)= 10所以我们打印这一行。(不需要检查19-18,好像任何字段值(8,9)是&gt; = 10我们打印这样的线条。

所以输出是

A.TXT:

dfbk|dfdag|sgvfd|ZD|zdf|2df|3w43f|ZZewd|11|19|fdgvdf|xz00|00|00

b.txt:

dfbk|dfdag|sgvfd|ZD|zdf|2df|3w43f|ZZewd|22|18|fdgvdf|xz00|00|00

3 个答案:

答案 0 :(得分:3)

您可以编写执行此操作的bash shell脚本:

while true; do
  read -r lineA <&3 || break
  read -r lineB <&4 || break

  vara_8=$(echo "$lineA" | cut -f8 -d "|")
  varb_8=$(echo "$lineB" | cut -f8 -d "|")
  vara_9=$(echo "$lineA" | cut -f9 -d "|")
  varb_9=$(echo "$lineB" | cut -f9 -d "|")

  if ((    vara_8-varb_8 > 10 || vara_8-varb_8 < -10
        || vara_9-varb_9 > 10 || vara_9-varb_9 < -10 )); then
    echo "$lineA" >> newA.txt
    echo "$lineB" >> newB.txt
  fi

done 3<a.txt 4<b.txt

答案 1 :(得分:3)

您可以使用awk执行此操作:

awk -F\| 'FNR==NR{x[FNR]=$0;eight[FNR]=$8;nine[FNR]=$9;next} {d1=eight[FNR]-$8;d2=nine[FNR]-$9;if(d1>10||d1<-10||d2>10||d2<-10){print x[FNR] >> "newa";print $0 >> "newb"}}' a.txt b.txt

<强>解释

-F将字段分隔符设置为管道符号。 FNR==NR之后的花括号中的内容仅适用于a.txt的处理。它表示将整行保存在由行号(x[])索引的数组FNR中,并保存数组eight[]中的第八个字段,也用行号索引。同样,字段9保存在数组nine[]中。

第二组花括号适用于处理文件b。它会计算差异d1d2。如果超过10,则该行将打印到每个文件newanewb

答案 2 :(得分:0)

短文件

使用Mark Setchell提供的方法。在下面的扩展和略微修改版本中看到:

parse.awk

FNR==NR { 
  x[FNR] = $0
  m[FNR] = $8
  n[FNR] = $9
  next
} 

{
  if(abs(m[FNR] - $8) || abs(n[FNR] - $9)) {
    print x[FNR] >> "newa"
    print $0     >> "newb"
  }
}

像这样运行:

awk -f parse.awk a.txt b.txt

对于大文件

上面的方法将a.txt读入内存。如果文件非常大,则变得不可行,并且需要进行流式解析。

可以一次完成,但这需要仔细处理来自a.txtb.txt的多路复用线。一种不易出错的方法是识别相关的行号,然后将它们提取到新文件中。最后一种方法的一个例子如下所示。

首先,您需要确定匹配的行:

# Extract fields 8 and 9 from a.txt and b.txt
paste <(awk -F'|' '{print $8, $9}' OFS='\t' a.txt) \
      <(awk -F'|' '{print $8, $9}' OFS='\t' b.txt) | 

# Check if it the fields matche the criteria and print line number
awk '$1 - $3 > n || $3 - $1 > n || $2 - $4 > n || $4 - $2 > 10 { print NR }' n=10 > linesfile

现在我们已准备好从a.txtb.txt中提取行,并且在数字排序后,我们可以使用extract.awk script proposed here(以下方便重复):

extract.awk

BEGIN {
  getline n < linesfile
  if(length(ERRNO)) {
    print "Unable to open linesfile '" linesfile "': " ERRNO > "/dev/stderr"
    exit
  }
}

NR == n { 
  print
  if(!(getline n < linesfile)) {
    if(length(ERRNO))
      print "Unable to open linesfile '" linesfile "': " ERRNO > "/dev/stderr"
    exit
  }
}

提取线条(可以并行运行):

awk -v linesfile=linesfile -f extract.awk a.txt > newa
awk -v linesfile=linesfile -f extract.awk b.txt > newb