Awk - 合并来自 2 个文件的数据,如果键匹配则打印到第 3 个文件
Awk - combine the data from 2 files and print to 3rd file if keys matched
场景:
- 我正在尝试编写 Awk 脚本。
- 我有两个文件。 File1(制表符分隔),File2(字符串)。
- 在File1中,我将01行的Field4+Field3+Field2组合起来做一个
File2 中字符串的 Field1 的引用键。
- 我能匹配和提取信息,但格式不对
要求
- 如果参考键匹配,我想将信息打印到File3.txt。我需要打印到 File3,其中格式为
- KEY MATCHED:File1 的第 01 -07 行后跟匹配的字符串
来自 File2,前缀为 77 等等。
- KEY NOT MATCHED: 如果键不匹配则把所有的
来自 File2 的不匹配记录仅具有前缀 99。
脚本:
awk -F'\t' -v OFS'\t' 'FNR==NR{a[substr([=10=],1,8)]=}
{if ( in a) printf ("77""\t"); else printf ("99""\t");print [=10=]}' \
File2.txt File1.txt > File3.txt
文件 1 :
01 89 68 5000
02 89 11
03 89 00
06 89 00
07 89 19 RT 0428
01 87 23 5100
02 87 11
04 87 9 02
03 87 00
06 87 00
07 87 11 RT 0428
01 83 23 4900
02 83 11
04 83 9 02
03 83 00
06 83 00
07 83 11 RT 0428
文件 2:
50006889 CCARD /3010 /E /C A87545457 / // ///11 ///
51002387 CCARD /3000 /E /S N054896334IV / // ///11 ///
51002390800666 CCARD /3000 /E /S N0978898IV / // ///11 ///
文件 3:当前输出
99 50006889 CCARD /3010 /E /C A87545457 / // ///11 ///
99
99 51002387 CCARD /3000 /E /S N054896334IV / // ///11 ///
99
99 51002390800666 CCARD /3000 /E /S N0978898IV / // ///11 ///
77 01 89 68 5000
99 02 89 11
99 03 89 00
99 06 89 00
99 07 89 19 RT
77 01 87 23 5100
99 02 87 11
99 04 87 9 02
99 03 87 00
99 06 87 00
99 07 87 11 RT 0428
99 01 83 23 4900
99 83 11
99 83 9 02
99 83 00
99 83 00
99 83 11 RT 0428
期望输出:
01 89 68 5000
02 89 11
03 89 00
06 89 00
07 89 19 RT 0428
77 50006889 CCARD /3010 /E /C A87545457 / // ///11 ///
01 87 23 5100
02 87 11
04 87 9 02
03 87 00
06 87 00
07 87 11 RT 0428
77 51002387 CCARD /3000 /E /S N054896334IV / // ///11 ///
99 51002390800666 CCARD /3000 /E /S N0978898IV / // ///11 ///
实际上,对于第 77 行和第 99 行,我需要整个字符串,但 77 和 99 仅在匹配键的开头。目前,如果字符串很长并继续到第二行,脚本也会将 77 和 99 放在第二行前面
我只想将 77 和 99 放在匹配代码的前面。
例如,以下是 Jonathan 更正后的 awk 代码的输出:
$ awk -f awk.script File2.txt File1.txt
01 89 68 5000
02 89 11
03 89 00
06 89 00
07 89 19 RT 0428
77 50006889 CCARD /3010 /E /C A87545457 / // ///11 ////3010 /E /C A87545457 / // ///11 ////3010 /E /C A87545457 / // ///11 ////3010 /E /C A87545457 / // ///11 ///
01 87 23 5100
02 87 11
04 87 9 02
03 87 00
06 87 00
07 87 11 RT 0428
77 51002387 CCARD /3000 /E /S N054896334IV / // ///11 ////3010 /E /C A87545457 / // ///11 ////3010 /E /C A87545457 / // ///11 ////3010 /E /C A87545457 / // ///11 ////3010 /E /C A87545457 / // ///11 ////3010 /E /C A87545457 / // ///11 ////3010 /E /C A87545457 / // ///11 ////3010 /E /C A87545457 / // ///11 ////3010 /E /C A87545457 / // ///11 ////3010 /E /C A87545457 / // ///11 ////3010 /E /C A87545457 / // ///11 ////3010 /E /C A87545457 / // ///11 ////3010 /E /C A87545457 / // ///11 ////3010 /E /C A87545457 / // ///11 ////3010 /E /C A87545457 / // ///11 ////3010 /E /C A87545457 / // ///11 ////3010 /E /C A87545457 / //
77 ///11 ////3010 /E /C A87545457 / // ///11 ////3010 /E /C A87545457 / // ///11 ////3010 /E /C A87545457 / // ///11 ///
01 83 23 4900
02 83 11
04 83 9 02
03 83 00
06 83 00
07 83 11 RT 0428
99 51002390800666 CCARD /3000 /E /S N0978898IV / // ///11 ////S N0978898IV / // ///11 ////S N0978898IV / // ///11 ////S N0978898IV / // ///11 ////S N0978898IV / // ///11 ////S N0978898IV / // ///11 ////S N0978898IV / // ///11 ////S N0978898IV / // ///11 ///////S N0978898IV / // ///11 ////S N0978898IV / // ///11 ////S N0978898IV / // ///11 ////S N0978898IV / // ///11 ///////S N0978898IV / // ///11 ////S N0978898IV / // ///11 ////S N0978898IV / // ///11 ////S N0978898IV / // ///11 ///////S N0978898IV
99 / // ///11 ////S N0978898IV / // ///11 ////S N0978898IV / // ///11 ////S N0978898IV / // ///11 ///////S N0978898IV / // ///11 ////S N0978898IV / // ///11 ////S N0978898IV / // ///11 ////S N0978898IV / // ///11 ///////S N0978898IV / // ///11 ////S N0978898IV / // ///11 ////S N0978898IV / // ///11 ////S N0978898IV / // ///11 ///////S N0978898IV / // ///11 ////S N0978898IV / // ///11 ////S N0978898IV / // ///11 ////S N0978898IV / // ///11 ///////S N0978898IV / // ///11 ////S N09
99 78898IV / // ///11 ////S N0978898IV / // ///11 ////S N0978898IV / // ///11 ///
$
您在阅读 File1.txt
之前正确阅读了 File2.txt
。不过,您需要忽略 File2.txt
中的空行。
FNR == NR && ! /^[[:space:]]*$/ { key = substr(, 1, 8); a[key] = [=10=]; next }
这使用第一个字段的前 8 个字符作为键,整行作为值。 next
确保不对行进行其他处理。
接下来的部分很繁琐。您需要在 </code> 中找到带有 <code>01
的行,并从中构建一个密钥。当您下一次获得 01
行时,您需要从 a
中打印出以 77 为前缀的行(并删除 a
中的条目)。
最后,您需要打印 a
中以 77 为前缀的行(并删除 a
中的条目)。然后,您需要处理 a
中剩余的任何条目,并为它们提供 99 前缀。
== "01" { if (code != 0)
{
if (code in a)
{
printf("77\t%s\n", a[code])
delete a[code]
}
}
code =
}
{ print }
END {
if (code in a)
{
printf("77\t%s\n", a[code])
delete a[code]
}
for (code in a)
printf("99\t%s\n", a[code])
}
显然,您可以使用比我刚才更少的白色 space,尽管您可能还需要添加一些分号。出于测试目的,我将上面的代码放入文件 awk.script
和 运行:
$ awk -f awk.script File2.txt File1.txt
01 89 68 5000
02 89 11
03 89 00
06 89 00
07 89 19 RT 0428
77 50006889 CCARD /3010 /E /C A87545457 / // ///11 ///
01 87 23 5100
02 87 11
04 87 9 02
03 87 00
06 87 00
07 87 11 RT 0428
77 51002387 CCARD /3000 /E /S N054896334IV / // ///11 ///
01 83 23 4900
02 83 11
04 83 9 02
03 83 00
06 83 00
07 83 11 RT 0428
99 51002390800666 CCARD /3000 /E /S N0978898IV / // ///11 ///
$
这看起来与您想要的非常相似。如果您想要在前一个输出块之后有一个空行,请在打印 77 前缀行的 if
块之后添加 printf("\n")
。如果您喜欢 I/O 重定向,您可以将其写入 File3.txt
。您可以将脚本嵌入单引号并将其添加到命令行以代替 -f awk.script
。如果您愿意,您也可以将整个脚本压缩到一个巨大的行中——但请不要这样做;做一个好的单行本太大了,这个程序的名字是awk
,而不是apl
。
场景:
- 我正在尝试编写 Awk 脚本。
- 我有两个文件。 File1(制表符分隔),File2(字符串)。
- 在File1中,我将01行的Field4+Field3+Field2组合起来做一个 File2 中字符串的 Field1 的引用键。
- 我能匹配和提取信息,但格式不对
要求
- 如果参考键匹配,我想将信息打印到File3.txt。我需要打印到 File3,其中格式为
- KEY MATCHED:File1 的第 01 -07 行后跟匹配的字符串 来自 File2,前缀为 77 等等。
- KEY NOT MATCHED: 如果键不匹配则把所有的 来自 File2 的不匹配记录仅具有前缀 99。
脚本:
awk -F'\t' -v OFS'\t' 'FNR==NR{a[substr([=10=],1,8)]=}
{if ( in a) printf ("77""\t"); else printf ("99""\t");print [=10=]}' \
File2.txt File1.txt > File3.txt
文件 1 :
01 89 68 5000
02 89 11
03 89 00
06 89 00
07 89 19 RT 0428
01 87 23 5100
02 87 11
04 87 9 02
03 87 00
06 87 00
07 87 11 RT 0428
01 83 23 4900
02 83 11
04 83 9 02
03 83 00
06 83 00
07 83 11 RT 0428
文件 2:
50006889 CCARD /3010 /E /C A87545457 / // ///11 ///
51002387 CCARD /3000 /E /S N054896334IV / // ///11 ///
51002390800666 CCARD /3000 /E /S N0978898IV / // ///11 ///
文件 3:当前输出
99 50006889 CCARD /3010 /E /C A87545457 / // ///11 ///
99
99 51002387 CCARD /3000 /E /S N054896334IV / // ///11 ///
99
99 51002390800666 CCARD /3000 /E /S N0978898IV / // ///11 ///
77 01 89 68 5000
99 02 89 11
99 03 89 00
99 06 89 00
99 07 89 19 RT
77 01 87 23 5100
99 02 87 11
99 04 87 9 02
99 03 87 00
99 06 87 00
99 07 87 11 RT 0428
99 01 83 23 4900
99 83 11
99 83 9 02
99 83 00
99 83 00
99 83 11 RT 0428
期望输出:
01 89 68 5000
02 89 11
03 89 00
06 89 00
07 89 19 RT 0428
77 50006889 CCARD /3010 /E /C A87545457 / // ///11 ///
01 87 23 5100
02 87 11
04 87 9 02
03 87 00
06 87 00
07 87 11 RT 0428
77 51002387 CCARD /3000 /E /S N054896334IV / // ///11 ///
99 51002390800666 CCARD /3000 /E /S N0978898IV / // ///11 ///
实际上,对于第 77 行和第 99 行,我需要整个字符串,但 77 和 99 仅在匹配键的开头。目前,如果字符串很长并继续到第二行,脚本也会将 77 和 99 放在第二行前面 我只想将 77 和 99 放在匹配代码的前面。
例如,以下是 Jonathan 更正后的 awk 代码的输出:
$ awk -f awk.script File2.txt File1.txt
01 89 68 5000
02 89 11
03 89 00
06 89 00
07 89 19 RT 0428
77 50006889 CCARD /3010 /E /C A87545457 / // ///11 ////3010 /E /C A87545457 / // ///11 ////3010 /E /C A87545457 / // ///11 ////3010 /E /C A87545457 / // ///11 ///
01 87 23 5100
02 87 11
04 87 9 02
03 87 00
06 87 00
07 87 11 RT 0428
77 51002387 CCARD /3000 /E /S N054896334IV / // ///11 ////3010 /E /C A87545457 / // ///11 ////3010 /E /C A87545457 / // ///11 ////3010 /E /C A87545457 / // ///11 ////3010 /E /C A87545457 / // ///11 ////3010 /E /C A87545457 / // ///11 ////3010 /E /C A87545457 / // ///11 ////3010 /E /C A87545457 / // ///11 ////3010 /E /C A87545457 / // ///11 ////3010 /E /C A87545457 / // ///11 ////3010 /E /C A87545457 / // ///11 ////3010 /E /C A87545457 / // ///11 ////3010 /E /C A87545457 / // ///11 ////3010 /E /C A87545457 / // ///11 ////3010 /E /C A87545457 / // ///11 ////3010 /E /C A87545457 / // ///11 ////3010 /E /C A87545457 / //
77 ///11 ////3010 /E /C A87545457 / // ///11 ////3010 /E /C A87545457 / // ///11 ////3010 /E /C A87545457 / // ///11 ///
01 83 23 4900
02 83 11
04 83 9 02
03 83 00
06 83 00
07 83 11 RT 0428
99 51002390800666 CCARD /3000 /E /S N0978898IV / // ///11 ////S N0978898IV / // ///11 ////S N0978898IV / // ///11 ////S N0978898IV / // ///11 ////S N0978898IV / // ///11 ////S N0978898IV / // ///11 ////S N0978898IV / // ///11 ////S N0978898IV / // ///11 ///////S N0978898IV / // ///11 ////S N0978898IV / // ///11 ////S N0978898IV / // ///11 ////S N0978898IV / // ///11 ///////S N0978898IV / // ///11 ////S N0978898IV / // ///11 ////S N0978898IV / // ///11 ////S N0978898IV / // ///11 ///////S N0978898IV
99 / // ///11 ////S N0978898IV / // ///11 ////S N0978898IV / // ///11 ////S N0978898IV / // ///11 ///////S N0978898IV / // ///11 ////S N0978898IV / // ///11 ////S N0978898IV / // ///11 ////S N0978898IV / // ///11 ///////S N0978898IV / // ///11 ////S N0978898IV / // ///11 ////S N0978898IV / // ///11 ////S N0978898IV / // ///11 ///////S N0978898IV / // ///11 ////S N0978898IV / // ///11 ////S N0978898IV / // ///11 ////S N0978898IV / // ///11 ///////S N0978898IV / // ///11 ////S N09
99 78898IV / // ///11 ////S N0978898IV / // ///11 ////S N0978898IV / // ///11 ///
$
您在阅读 File1.txt
之前正确阅读了 File2.txt
。不过,您需要忽略 File2.txt
中的空行。
FNR == NR && ! /^[[:space:]]*$/ { key = substr(, 1, 8); a[key] = [=10=]; next }
这使用第一个字段的前 8 个字符作为键,整行作为值。 next
确保不对行进行其他处理。
接下来的部分很繁琐。您需要在 </code> 中找到带有 <code>01
的行,并从中构建一个密钥。当您下一次获得 01
行时,您需要从 a
中打印出以 77 为前缀的行(并删除 a
中的条目)。
最后,您需要打印 a
中以 77 为前缀的行(并删除 a
中的条目)。然后,您需要处理 a
中剩余的任何条目,并为它们提供 99 前缀。
== "01" { if (code != 0)
{
if (code in a)
{
printf("77\t%s\n", a[code])
delete a[code]
}
}
code =
}
{ print }
END {
if (code in a)
{
printf("77\t%s\n", a[code])
delete a[code]
}
for (code in a)
printf("99\t%s\n", a[code])
}
显然,您可以使用比我刚才更少的白色 space,尽管您可能还需要添加一些分号。出于测试目的,我将上面的代码放入文件 awk.script
和 运行:
$ awk -f awk.script File2.txt File1.txt
01 89 68 5000
02 89 11
03 89 00
06 89 00
07 89 19 RT 0428
77 50006889 CCARD /3010 /E /C A87545457 / // ///11 ///
01 87 23 5100
02 87 11
04 87 9 02
03 87 00
06 87 00
07 87 11 RT 0428
77 51002387 CCARD /3000 /E /S N054896334IV / // ///11 ///
01 83 23 4900
02 83 11
04 83 9 02
03 83 00
06 83 00
07 83 11 RT 0428
99 51002390800666 CCARD /3000 /E /S N0978898IV / // ///11 ///
$
这看起来与您想要的非常相似。如果您想要在前一个输出块之后有一个空行,请在打印 77 前缀行的 if
块之后添加 printf("\n")
。如果您喜欢 I/O 重定向,您可以将其写入 File3.txt
。您可以将脚本嵌入单引号并将其添加到命令行以代替 -f awk.script
。如果您愿意,您也可以将整个脚本压缩到一个巨大的行中——但请不要这样做;做一个好的单行本太大了,这个程序的名字是awk
,而不是apl
。