【问题标题】:grep/ack on Mac OS X finding multiple strings and respecting file typesMac OS X 上的 grep/ack 查找多个字符串并尊重文件类型
【发布时间】:2016-02-08 18:10:55
【问题描述】:

我想在满足以下条件的 Mac OS X 上运行 grep

  • 搜索所有以*.R*.r为扩展名的文件,忽略其他文件
  • 查找字符串:wordAwordB 考虑到字符串可能以 someRubbishWordARubbish 格式出现(这是有效匹配)
  • 只列出两个字符串出现的文件不考虑顺序
  • 打印出现字符串的行
  • 用颜色突出显示找到的单词
  • 将文件名打印为标题和标题下的行。我受到ack 选项的启发。
  • 忽略大小写

方法

我正在考虑使用 this discussion 并从以下 grep 语法开始:

grep --include=*.R -r setHeader .

然后将其与以下内容结合起来:

grep 'word1\|word2\|word3' /path

但是,我希望 cmets 确保正确评估上述所有标准。

^(.*)(facet|map)(.*)(map|facet)(.*)$

regex101


确认

运行ack -f 表明将搜索*.R 文件,因此将接受使用ack 的解决方案。例如,运行:

ack wordA --colour -i -H --rr

获得关于 wordA 的预期结果。我正在考虑将它与here 讨论的解决方案结合起来,但我想使用 AND 而不是 OR 并忽略字符串可能出现的顺序。我进一步尝试:

ack --match wordA --match wordB  --colour -i -H --rr

但这只会产生wordB的结果。

【问题讨论】:

    标签: regex macos bash grep ack


    【解决方案1】:

    这是一个结合了紧密命名的 awkack 命令的脚本:

    find . -iname '*.r' | while read file; do
        awk '
            BEGIN { IGNORECASE=1; sawWordA = 0; sawWordB = 0 }
            /wordA/ { sawWordA = 1 }
            /wordB/ { sawWordB = 1 }
            sawWordA && sawWordB { exit } # stop reading lines if both matches seen
            END { exit !(sawWordA && sawWordB) }
            ' \
            "${file}" \
        && ack --nofilter -H -i 'wordA|wordB' "${file}"
    done
    

    awk 命令...

    • 仅列出同时出现两个字符串的文件,无论顺序如何
    • 忽略大小写

    ...以及 ack 命令...

    • 打印出现字符串的行
    • 用颜色突出显示找到的单词
    • 根据 ack 选项将文件名打印为标题和标题下的行
    • 忽略大小写

    如果有搜索字符串匹配,awk 脚本会设置标志。如果两个字符串都匹配,则 sn-p exit !(sawWordA && sawWordB) 将返回 0。如果 awk 返回 0,则 ack 命令运行。

    ack --nofilter 选项告诉 ack 避免从 STDIN 读取。否则,ack 将尝试使用 read 命令正在使用的 STDIN。

    在 cmets 中,Konrad 询问在 shell 脚本中传递变量时如何使用上述代码。下面是一个例子:

    #!/bin/sh
    
    if [ $# -ne 2 ]; then
        echo Usage: $0 {string1} {string2}
        E_BADARGS=65
        exit $E_BADARGS
    fi
    
    find . -maxdepth 1 -iname '*.r' | while read file; do
        awk "
            BEGIN { IGNORECASE=1; sawArg1 = 0; sawArg2 = 0 }
            /$1/ { sawArg1 = 1 }
            /$2/ { sawArg2 = 1 }
            sawArg1 && sawArg2 { exit } # stop reading lines if both matches seen
            END { exit !(sawArg1 && sawArg2) }
            " \
            "${file}" \
        && ack --nofilter -H -i "$1|$2" "${file}"
    done
    

    上面的例子没有对提供给脚本的参数中的任何特殊字符进行转义。如果需要转义,可以根据需要修改脚本。

    【讨论】:

    • 如果我想在bash 中调用它并将参数传递给wordAwordB,我将如何修改此脚本。我认为我必须做 "$1""$2" 但它应该寻找语法 wordA|wordB?
    • @Konrad 我添加了用于将变量传递到 shell 脚本的示例代码。
    • 非常感谢,它是一个非常有用的工具。
    【解决方案2】:

    嗯,这非常低效,但假设您搜索的不是大目录,这应该可以。

    find . -iname "*.r"  | while read file
    do 
    if (grep -qi "wordB" $file && grep -qi "wordA" $file)
      then
      echo "======== $file ======="
      grep --color=auto -iE "wordA|wordB" $file
      fi
    done
    

    【讨论】:

    • 非常感谢您提供解决方案。我可能在一个大目录上运行它,但任何解决方案都比没有解决方案好。我想我会将它保存为 bash 脚本,因为它会很方便。我想知道,是否可以在 grep 中使用 --include 而不是在开始时运行 find ?跨度>
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-20
    • 2016-06-12
    • 2012-05-16
    • 2012-06-10
    • 2023-03-24
    • 1970-01-01
    相关资源
    最近更新 更多