grep 使用来自其他文件的单词匹配行中的特定位置

asi*_*swt 5 unix shell grep

我有 2 个文件

文件 1:

12342015010198765hello
12342015010188765hello
12342015010178765hello
Run Code Online (Sandbox Code Playgroud)

其每一行都包含固定位置的字段,例如,位置13 - 17用于account_id

文件2:

98765
88765
Run Code Online (Sandbox Code Playgroud)

其中包含account_ids的列表。

在 Korn Shell 中,我想从 file1 打印其位置13 - 17account_idfile2中的一个匹配的行。

我做不到

grep -f file2 file1
Run Code Online (Sandbox Code Playgroud)

因为account_id在 file2 中可以匹配其他位置的其他字段。

我曾尝试在 file2 中使用模式:

^.{12}98765.*
Run Code Online (Sandbox Code Playgroud)

但没有用。

Joh*_*024 5

使用 awk

$ awk 'NR==FNR{a[$1]=1;next;} substr($0,13,5) in a' file2 file1
12342015010198765hello
12342015010188765hello
Run Code Online (Sandbox Code Playgroud)

这个怎么运作

  • NR==FNR{a[$1]=1;next;}

    FNR 是迄今为止从当前文件读取的行数,NR 是迄今为止读取的总行数。因此,如果FNR==NR,我们正在读取第一个文件file2.

    file2 中的每个 ID 都保存在 array 中a。然后,我们跳过其余的命令并跳转到该next行。

  • substr($0,13,5) in a

    如果我们到达这个命令,我们正在处理第二个文件,file1.

    如果从位置 13 开始的 5 个字符长的子字符串在 array 中,则此条件为真a。如果条件为真,则 awk 执行默认操作,即打印该行。

使用 grep

你提到尝试

grep '^.{12}98765.*' file2
Run Code Online (Sandbox Code Playgroud)

这使用扩展的正则表达式语法,这意味着这-E是必需的。此外,.*最后匹配没有任何价值:它将始终匹配。因此,尝试:

$ grep -E '^.{12}98765' file1
12342015010198765hello
Run Code Online (Sandbox Code Playgroud)

要获得这两行:

$ grep -E '^.{12}[89]8765' file1
12342015010198765hello
12342015010188765hello
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为[89]8765恰好与 file2 中感兴趣的 ID 匹配。当然,awk 解决方案在匹配的 ID 方面提供了更大的灵活性。