【问题标题】:how to use && with grep in bash如何在 bash 中使用 && 和 grep
【发布时间】:2016-06-03 19:39:20
【问题描述】:

我想检查 bash 中是否存在文件中的多行。

所以我使用grep -q,它只适用于一行:

if grep -q string1 "/path/to/file";then
  echo 'exists'
else
  echo 'does not exist'
fi

我尝试了很多不同的组合,例如:

if grep -q [ string1 ] && grep -q [ string2 ] "path/to/file";then

我也试过-E:

grep -E 'pattern1' filename | grep -E 'pattern2'

但似乎没有任何效果。有什么想法吗?

【问题讨论】:

  • grep -q string_1 file && grep -q string_2 file?
  • @iruvar 将其作为答案发布
  • 这个我也试过了,但是脚本永远不会完成
  • @PaulBernhardWagner,这可能是因为您错过了在string1 之后指定file
  • 天哪,我觉得自己太笨了,这行得通。但这意味着在 bash 中不可能写得比这更简单?就像在其他语言中你只有if (cond1 && cond2) ....

标签: linux bash shell grep


【解决方案1】:

您可以使用此gnu-awk 命令断言文件中存在多个字符串,而不是运行多个grep 命令:

awk -v RS='\\Z' '/string1/ && /string2/ && /string3/{e=1} END{exit !e}' file &&
echo 'exists' || echo 'does not exist'
  • RS=\Z 将使 awk 读取单个记录分隔符中的所有输入
  • 在多个搜索词之间使用&& 将确保所有搜索词都存在于输入文件中
  • 仅当输入文件中存在所有 3 个搜索词时,才会打印 exists

【讨论】:

  • 执行单条记录似乎有点内存效率低下。这里有原因吗? (我通过“多行 [...] 存在”阅读了这个问题,以指定各个模式将匹配单独的行)。
  • 我们正在尝试寻找跨行的模式。我还没有做基准测试,但 IMO 它会比grep -q string1 file && grep -q string2 file && grep -q string3 file 更有效率
  • 我绝对同意这比多个 grep 的 IO 效率更高,我只是不明白为什么你没有让你的 awk 代码逐行应用模式,每当设置一个标志任何模式都匹配(可能早早退出),因此在处理大量输入时放宽了内存需求。
  • 是的,我建议在匹配所有条件时退出 0。
  • 作为一种通用且内存效率更高的解决方案,可以使用:awk -v words='kw1;kw2;kw3' 'BEGIN{n=split(words, w, /;/); for (i=1; i<=n; i++) p[w[i]]} {for (i=1; i<=n; i++) if (w[i] in p && $0 ~ w[i]) delete p[w[i]]; if (length(p)==0) {e=1; exit 0}} END{exit !e}' file
【解决方案2】:

由于@iruvar 没有发布他的评论作为答案,我会把它放在这里:

grep -q string_1 file && grep -q string_2 file

现在,这是我的贡献。是@anubhava 的计算更复杂的awk 答案,它只读取文件一次,比@iruvar 的简单答案(读取文件三遍)快吗?

awk          11.730 s
grep && grep  0.258 s

没有。

这肯定取决于文件系统与 cpu 的速度,以及缓存的速度,但在我的系统上,这可能是典型的 B+/A- 工作站,grep kw1 file && grep kw2 file && grep kw3 file 的速度大约是 50 倍@anubhava 的 awk 解决方案。这在 ssd 和主轴突袭中都是如此。 (详情:测试文件500万行,160M,第一行有kw1,第250万有kw2,第5百万有kw3。)

可以进行一些简单的优化,例如,如果您可以通过匹配整行来解决您的问题,那么就这样做(使用grep -x);在这种情况下,它的速度是原来的两倍。

对于许多(例如,>1,000)文件,使用grep -lxargs 更快:

grep -l kw1 *.txt | xargs grep -l kw2 | xargs grep -q kw3

相对于循环:

for f in *.txt; do
    grep -q kw1 $f && grep -q kw2 $f && grep -q kw3 $f
done

使用相同的测试文件,grep -l | xargs grep 耗时 0.258 秒,就像grep && grep。有两个测试文件,它仍然没有比grep && grep 快。有 2000 个测试文件,每个文件有 5000 行,其中没有一个包含任何匹配项,grep -l | xargs grep 的速度是grep && grep 的 10 倍左右。

【讨论】:

    【解决方案3】:

    您的问题存在一些歧义,但假设您希望 pattern_1 和 pattern_2 存在于一个文件中(不在同一行),那么您可以这样做。

    for file in *; do
      egrep -q pattern_1 $file && egrep -q pattern_2 $file && echo $file
    done
    

    【讨论】:

    • 需要更多报价。 "$file",而不是 $file,否则对于带有空格的文件名,这将严重失败。
    • 如果你有一个用touch '*.txt' 创建的文件,它的行为也会很奇怪——它会 grep 所有文本文件,并列出所有文本文件,而不仅仅是一个单独的文件它出现了。行情是你的朋友。
    【解决方案4】:

    使用grep -p,您可以在同一行匹配多个模式:

    grep -P '(?=.*string1)(?=.*string2)' file
    

    上面将打印匹配string1string2 的行。

    (?=...) 是一个positive lookaheads,它匹配一个模式,但不使其成为匹配的一部分。

    -z 会吞下整个文件:

    % seq 1 100 | grep -qzP '(?=.*1)(?=.*5)'; echo $?
    0
    % seq 1 100 | grep -qzP '(?=.*1)(?=.*a)'; echo $?
    1
    

    【讨论】:

    • 我认为你可以使用grep -e 'pattern1' -e 'pattern2'
    • @BenjaminW。这不会做一个逻辑或吗?我认为 OP 想要逻辑与
    • 啊,是的,你是对的,看起来他想要 AND。我的错。
    【解决方案5】:

    你可以这样做:

    if grep -q 'string1' /path/to/file; then
        if grep -q 'string2' /path/to/file; then
            echo exists
         else
            echo 'does not exist'
     else
         echo 'does not exist'
     fi
    

    或者:

    grep -q 'string1' /path/to/file &&
    grep -q 'string2' /path/to/file &&
    echo exists ||
    echo 'does not exist'
    

    【讨论】:

    • 我认为他需要文件中存在所有模式才能成功
    • 这是 OR,不是 AND。
    • a && b && c || d 不是写if a && b; then c; else d; fi 的简洁方式。如果标准输出关闭并且echo exists 失败怎么办? (您继续尝试回显“不存在”,即使内容实际上已找到)。
    • 我也想到了第一个解决方案,但是代码中有两次echo 'does not exist'
    【解决方案6】:

    您可以使用“-q”使用 grep 进行搜索

    if  grep -q string1 "/path/to/file" &&  grep -q string2 "/path/to/file";then
          echo 'exists'
        else
          echo 'does not exist'
        fi 
    

    【讨论】:

    • 这是一个 OR;该问题要求 AND(预期模式在不同的行上相互匹配)。
    • || 仍然是 OR - 而如果您将其修改为 &&,您的答案将在 Jahid 之前。
    • 我的错误现在更新了,使用“&&”
    猜你喜欢
    • 2016-02-04
    • 2018-05-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-03
    • 1970-01-01
    • 2013-06-21
    • 1970-01-01
    相关资源
    最近更新 更多