awk:在包含pattern2的文件中找到匹配的pattern1

时间:2017-09-01 22:57:52

标签: bash shell awk sed scripting

我正在解析大量文件并搜索与awk的对应关系。 我很难找到一种方法来查找包含pattern1和仅在此文件中搜索pattern2的文件。

示例:

MacOSX

我想要的结果应该是:

file1:  
text xyz 122e345a rxyc  
abc 25b57790c

file 2:  
text tio 36e79a89 opgb  
abc b0894e35o  

file 3:  
text diowps aaaacc  
abc 122e345a  

虽然我的第一个模式是:

25b57790c

我现在唯一的解决方案是分2步完成:

122e345a

我可以像这样一个班轮:

FILE=$(awk '$3 == "122e345a" {print FILENAME}' * )  
awk '$1 == "abc" {print $2}' $FILE

但是我想避免双awk调用,不能在一个awk命令中完成吗?

2 个答案:

答案 0 :(得分:2)

file != FILENAME       { found = 0 }
         $3 == a       { found = 1; file = FILENAME }
found && $1 == b       { print $2  }

或者,对于GNU awk

BEGINFILE              { found = 0 }
         $3 == a       { found = 1 }
found && $1 == b       { print $2  }

这与markp的解决方案非常相似(并做出类似的假设),但可以在不使用shell循环的情况下在任意数量的输入文件上运行:

$ awk -f script.awk a="122e345a" b="abc" file[123]
25b57790c

脚本还假设您要搜索的模式实际上是特定列中的固定字符串(如问题所示)。

因为没有办法'#34;倒带" awk中的文件,如果要在第一个字符串之前找到第二个字符串,则需要将文件传递两次。问题末尾的代码本身就是一个解决方案。

或者,您可以将整个文件保存在变量中,一旦找到第一个字符串(此处未包含该解决方案),就可以查看该文件。

答案 1 :(得分:1)

注意:已更新以显示所需模式的完全匹配;如果目标是显示部分匹配,则相应地替换搜索模式:

partial matching:  $3 ~ /122e345a/
                   $1 ~ /abc/

complete matching: $3 == "122e345a"
                   $1 == "abc"

假设:

  • 第一次搜索包括查找第三个字段与字符串"122e345a"完全匹配的行,如果找到则...
  • 查找第一个字段与字符串"abc"完全匹配的行,如果找到则...
  • 打印第二个字段(包含字符串"abc"的行)
  • 的内容
  • 字符串"122e345a"首先出现在文件中,字符串"abc"显示a)与第一个字符串在同一行中,或者b)在后续行中显示
  • 如果字符串"abc"在文件中多次出现(在找到字符串"122e345a"之后),那么每次出现字符串"abc"都会导致print命令发出

一种可能的awk解决方案:

awk '
BEGIN                            { found = 0 }
                $3 == "122e345a" { found = 1 }
(found == 1) && $1 == "abc"      { print $2  }
' <file>
  • 设置变量found=0;由于这是BEGIN块的一部分,因此仅在处理新文件的开始时执行(即,我们正在初始化found
  • 如果在一行的第三个字段中找到字符串"122e345a",则设置found = 1
  • 如果我们的变量found设置为1,并且在一行的第一个字段中找到字符串"abc",则打印该行的第二个字段

注意:您可以将awk脚本作为多行构造(上图)或单行提交,例如:

awk 'BEGIN { found = 0 } $3 == "122e345a" { found = 1 } (found == 1) && $1 == "abc" { print $2 }' <file>

使用您的示例文件(file1/file2/file3),并添加file4作为file1的副本并切换行:

$ cat file4
abc 25b57790c
text xyz 122e345a rxyc

$ for f in file*
do
    echo "++++++++++++++ file : $f"
    awk 'BEGIN { found = 0 } $3 == "122e345a" { found = 1 } (found == 1) && $1 == "abc" { print $2 }' $f
done

++++++++++++++ file : file1
25b57790c
++++++++++++++ file : file2
++++++++++++++ file : file3
++++++++++++++ file : file4

请注意,虽然file4的行与两个搜索字符串都匹配,但字符串"122e345a"会在字符串"abc"之后显示,这违反了其中一个假设,因此file4我们的搜索失败了。