awk模式将一个文件与另一个文件匹配,然后将差异保存在新文件中


$ cat File1
781789
989778
898989
$ cat File2
AA^ABB^ACC^A781789^B781782^AEE^AFF^A781789^B781782AA^ABB^ACC^A7817891^B7817821^AEE^AFF^A7817891^B781782AA^ABB^ACC^A781789^B898989^AEE^AFF^A781789^B898989^B898923
  • 字段分隔符:"A";或";\x01">
  • 记录分隔符:"^B";或";\x02">

我想创建一个结果文件";文件3";其中记录来自";文件1";不匹配"0"中列号4和7的任何记录;文件2";。如果记录匹配,则不要考虑。

预期输出:

$ cat File3
AA^ABB^ACC^A7817891^B7817821^AEE^AFF^A7817891^B781782

尝试使用以下awk代码,其中我能够解析";文件2";具有字段分隔符,但不能匹配来自"的记录;文件1";至";文件2";。

awk 'BEGIN { FS="x01"} NR==FNR{A[$4]~/$0/;next}{print A[$0]} File1 File2 > File3'

awk 'BEGIN { FS="x01"} NR==FNR{A[$7]~/$0/;next}{print A[$0]} File1 File2 > File3'

请求帮助。

我已经更新了我的file2,并用相应的控制字符0x010x02替换了文字字符串^A^B。我还验证了我的file2只有一行数据。

我们将从awk脚本开始验证我们已经正确定义了字段和记录分隔符,显示每个记录中有多少字段,并显示每个字段的内容:

awk '
BEGIN   {  FS="x01" ;  RS="[x02|n]"           # define input field/record delimiters,
# add "n" in case the sole line ends in a "n"
OFS="-"    ; ORS="n"   }              # define output field/record delimiters
# solely for visual purposes of this test
{ print $1, $2, $3, $4, $5, $6, $7 }     # print line
' file2

这将生成:

A-BB-CC-781789---                # 1st 6 records have 4 fields
781782-EE-FF-781789---
781782A-BB-CC-7817891---         # we should see this record in our final output (below)
7817821-EE-FF-7817891---         # we should see this record in our final output (below)
781782A-BB-CC-781789---
898989-EE-FF-781789---
898989------                     # last 2 records have 1 field
898923------

file1添加到混合中(将值存储在数组中(,添加字段#4的测试,并添加用于打印字段的代码和用于stdout:的控制代码

awk '
BEGIN       { FS="x01"                # define input field separator
RS="[x02|n]"           # define input record separator
ORS=""                   # will dynamically modify output record separator
}
FNR==NR     { arr[$1] ; next }         # store file1 values in array arr[]
$4 != ""    { if ($4 in arr)           # if field 4 (file2) is in arr[] (ie, field 4 is in file1)
next                  # then skip
else                     # else add current line to our variable
{ OFS=""
printf "%s", ORS
for (i=1; i<=NF; i++)    # process variable number of fields
{ printf "%s%s", OFS, $(i)
OFS="x01"
}
ORS="x02"
}
}
' file1 file2

注意:是的,这有点冗长,因为我想确保更容易理解各个步骤。

这将生成:

781782ABBCC78178917817821EEFF7817891

注意:这与OP的建议输出不匹配,但无法判断这是因为OP的输出是从不同的输入集生成的,还是因为在创建问题时原始剪切部分有问题;该输出与第一个CCD_ 11命令的输出中标记的2个记录匹配(如上(。

通过od -c(即awk '...' file1 file2 | od -c(传递输出:

0000000   7   8   1   7   8   2   A 001   B   B 001   C   C 001   7   8
0000020   1   7   8   9   1 002   7   8   1   7   8   2   1 001   E   E
0000040 001   F   F 001   7   8   1   7   8   9   1
0000053

注意:我假设输出应该如图所示结束。。。既没有x02也没有CCD_ 15;OP可以添加一个END { printf ... }块,以便根据需要在行/文件的末尾添加任何附加字符。

我不精通awk,但以下是如何使用sedgrep:

egrep -v $'^(w+x01){3}((w+x01){3})?('$(sed 's/ +/|/g' < file1)$')[x02x01]' file2 > file3

命令egrep -v … file2file2上的正则表达式匹配,但会精确地打印出不匹配的行(反转(。我们从以下部分组成正则表达式:

  1. 一个单词以\x01结尾三次,所以我们最后进入第4列
  2. 可选地,一个单词以\x01结尾的另外三次,因此我们在第7列结束
  3. file1中的任何记录
  4. 记录分隔符\x02或字段分隔符\x01(如果是列中的最后一条记录(

要从file1获得第(3(部分,我们使用sed将文件中记录之间的所有空格替换为管道。这产生了格式(abc|def|ghi),该格式在正则表达式中表示一组备选方案。

以下是我在awk:中的操作方法

awk 'FNR==NR { r[$0] = 1; next }
!((NF >= 4 && $4 in r) || (NF >= 7 && $7 in r))' 
file1 FS='x01' RS='x02' ORS='x02' file2

但是,您的示例数据并不能产生所列的预期输出。特别是,file2的第三条记录是781782AA^ABB^ACC^A7817891,它在第4列中的值没有出现在file1中(没有第7列;没有一条记录有那么多列。有些记录甚至没有4!(,因此应该根据您的描述包含在输出中。

相关内容

最新更新