Grep在一行中搜索两个单词

我一直试图找到一种方法来过滤其中包含“柠檬”和“米”字样的行。 我知道如何找到“柠檬”或“米饭”而不是其中的两个。 它们不需要紧挨着另一个,只需要一行文本。

“两者都在同一条线上”意味着“’米饭’后跟随机字符,然后是’柠檬’或者相反”。

在正则表达是rice.*lemonlemon.*rice 。 您可以使用|组合它 :

 grep -E 'rice.*lemon|lemon.*rice' some_file 

如果要使用普通正则表达式而不是扩展名( -E ),则需要在|之前使用反斜杠 :

 grep 'rice.*lemon\|lemon.*rice' some_file 

对于更快速变得有点冗长的单词,通常使用grep多次调用会更容易,例如:

 grep rice some_file | grep lemon | grep chicken 

您可以将第一个grep命令的输出传递给另一个grep命令,该命令将匹配这两个模式。 所以,你可以这样做:

 grep   | grep  

要么,

 cat  | grep  | grep  

例:

让我们在文件中添加一些内容:

 $ echo "This line contains lemon." > test_grep.txt $ echo "This line contains rice." >> test_grep.txt $ echo "This line contains both lemon and rice." >> test_grep.txt $ echo "This line doesn't contain any of them." >> test_grep.txt $ echo "This line also contains both rice and lemon." >> test_grep.txt 

该文件包含什么:

 $ cat test_grep.txt This line contains lemon. This line contains rice. This line contains both lemon and rice. This line doesn't contain any of them. This line also contains both rice and lemon. 

现在,让我们想要的是:

 $ grep rice test_grep.txt | grep lemon This line contains both lemon and rice. This line also contains both rice and lemon. 

我们只得到两个模式匹配的行。 您可以扩展它并将输出传递给另一个grep命令以进行进一步的“AND”匹配。

虽然问题是’grep’,但我认为发布一个简单的’awk’解决方案可能会有所帮助:

 awk '/lemon/ && /rice/' 

除了’和’之外,可以使用更多单词或其他布尔表达式轻松扩展。

以任何顺序查找匹配的另一个想法是使用:

grep与-P (Perl-Compatibility)选项和正向前瞻性正则表达式(?=(regex))

 grep -P '(?=.*?lemon)(?=.*?rice)' infile 

或者您可以在下面使用,而不是:

 grep -P '(?=.*?rice)(?=.*?lemon)' infile 
  • .*? 意味着匹配任何字符. 出现零次或多次*而它们是可选的,后跟一个模式( ricelemon )。 的? 在它之前使一切都是可选的(意味着所有匹配的零或一次.*

(?=pattern) :正向前瞻:正向前瞻构造是一对括号,左括号后跟一个问号和一个等号。

所以这将返回包含lemonrice所有行以随机顺序。 这也将避免使用| s和加倍的grep s。


外部链接:
高级Grep主题
积极的前瞻 – 设计师的GREP

 grep -e foo -e goo 

将返回foo或goo的匹配项

如果我们承认提供非基于grep的答案是可以接受的,就像基于awk的上述答案一样,我会提出一个简单的perl行,如:

 $ perl -ne 'print if /lemon/ and /rice/' my_text_file 

搜索可以忽略一些/所有单词的情况,如/lemon/i and /rice/i 。 在大多数Unix / Linux机器上,无论如何都安装了perl和awk。

这是一个自动化grep管道解决方案的脚本:

 #!/bin/bash # Use filename if provided as environment variable, or "foo" as default filename=${filename-foo} grepand () { # disable word splitting and globbing IFS= set -f if [[ -n $1 ]] then grep -i "$1" ${filename} | filename="" grepand "${@:2}" else # If there are no arguments, assume last command in pipe and print everything cat fi } grepand "$@"