Match two strings in one line with grep
我试图使用
1 | grep 'string1\|string2' filename |
那么我如何只与包含两个字符串的行匹配
我认为这就是你要找的东西:
1 | grep -E"string1|string2" filename |
我认为答案是这样的:
1 | grep 'string1.*string2\|string2.*string1' filename |
只匹配两者都存在的情况,而不是一个或另一个或两者。
您可以使用
或者,
要在任何地方搜索包含所有单词的文件:
1 | grep -ril \'action\' | xargs grep -il \'model\' | xargs grep -il \'view_type\' |
第一个grep启动递归搜索(
随后的greps搜索其他术语,保留不区分大小写并列出匹配的文件。
您将获得的最终文件列表将是包含这些术语的文件,可以按文件中的任何顺序排列。
如果你有一个
1 | grep -P '(?=.*string1)(?=.*string2)' |
它具有处理重叠字符串的优点。使用
1 | perl -ne 'print if /string1/ && /string2/' |
你的方法几乎是好的,只缺少-w
1 | grep -w 'string1\|string2' filename |
你可以尝试这样的事情:
1 | (pattern1.*pattern2|pattern2.*pattern1) |
正则表达式中的
1 | grep 'string1' filename | grep 'string2' |
这会将第一个命令的结果传递给第二个grep。这应该只给你两条线匹配。
正如人们建议使用perl和python以及复杂的shell脚本,这里有一个简单的awk方法:
1 | awk '/string1/ && /string2/' filename |
看了接受答案的评论:不,这不做多行;但那也不是问题的作者所要求的。
找到仅以6个空格开头的行并完成:
1 2 3 4 | cat my_file.txt | grep -e '^ .*(\.c$|\.cpp$|\.h$|\.log$|\.out$)' # .c or .cpp or .h or .log or .out -e '^ .*[0-9]\{5,9\}$' # numers between 5 and 9 digist > nolog.txt |
1 | grep ‘string1\|string2’ FILENAME |
GNU grep版本3.1
假设我们需要在文件测试文件中找到多个单词的计数。
有两种方法可以解决它
1)使用带有正则表达式匹配模式的grep命令
1 | grep -c '\<\(DOG\|CAT\)\>' testfile |
2)使用egrep命令
1 | egrep -c 'DOG|CAT' testfile |
使用egrep,您不必担心表达式,只需通过管道分隔符分隔单词。
不要尝试使用grep,而是使用awk。要在grep中匹配2个正则表达式R1和R2,您认为它将是:
1 | grep 'R1.*R2|R2.*R1' |
而在awk它是:
1 | awk '/R1/ && /R2/' |
但是如果
1 2 3 | $ echo 'theatre' | grep 'the.*heat|heat.*the' $ echo 'theatre' | awk '/the/ && /heat/' theatre |
你必须使用2个greps和一个管道:
1 2 | $ echo 'theatre' | grep 'the' | grep 'heat' theatre |
当然,如果你实际上要求它们是分开的,你总是可以在awk中写入与grep中使用的相同的正则表达式,并且有其他awk解决方案不涉及在每个可能的序列中重复正则表达式。
抛开这一点,如果您想扩展您的解决方案以匹配3个正则表达式R1,R2和R3,该怎么办?在grep中,这将是这些糟糕的选择之一:
1 2 | grep 'R1.*R2.*R3|R1.*R3.*R2|R2.*R1.*R3|R2.*R3.*R1|R3.*R1.*R2|R3.*R2.*R1' file grep R1 file | grep R2 | grep R3 |
而在awk中,它是简洁,明显,简单,高效的:
1 | awk '/R1/ && /R2/ && /R3/' |
现在,如果您真的想要匹配文字字符串S1和S2而不是正则表达式R1和R2,该怎么办?你只是不能在一次grep调用中做到这一点,你必须在调用grep之前编写代码以逃避所有RE metachars:
1 2 3 | S1=$(sed 's/[^^]/[&]/g; s/\^/\\^/g' <<< 'R1') S2=$(sed 's/[^^]/[&]/g; s/\^/\\^/g' <<< 'R2') grep 'S1.*S2|S2.*S1' |
或者再次使用2个greps和一个管道:
1 | grep -F 'S1' file | grep -F 'S2' |
这又是糟糕的选择,而使用awk你只需使用字符串运算符而不是regexp运算符:
1 | awk 'index($0,S1) && index($0.S2)' |
现在,如果你想在一个段落而不是一行中匹配2个正则表达式怎么办?在awk中无法完成,在awk中无关紧要:
1 | awk -v RS='' '/R1/ && /R2/' |
整个文件怎么样?再次无法用awk中的grep和trivial完成(这次我使用GNU awk来实现多字符RS的简洁性,但是在任何awk中代码都不多,或者你可以选择一个你不知道的控件字符在RS的输入中做同样的事情):
1 | awk -v RS='^$' '/R1/ && /R2/' |
所以 - 如果你想在一行或一个段落或文件中找到多个正则表达式或字符串,那么不要使用grep,请使用awk。
1 | grep '(string1.*string2 | string2.*string1)' filename |
将以任何顺序获得string1和string2的行
1 | grep -i -w 'string1\|string2' filename |
这适用于精确的单词匹配和匹配不区分大小写的单词,因为使用了-i
以下是使用带有多个模式的
1 | git grep --all-match --no-index -l -e string1 -e string2 -e string3 file |
您还可以将模式与布尔表达式(如
检查
--all-match When giving multiple pattern expressions, this flag is specified to limit the match to files that have lines to match all of them.
--no-index Search files in the current directory that is not managed by Git.
-l /--files-with-matches /--name-only Show only the names of files.
-e The next parameter is the pattern. Default is to use basic regexp.
其他参考考虑:
--threads Number of grep worker threads to use.
-q /--quiet /--silent Do not output matched lines; exit with status 0 when there is a match.
要更改图案类型,您还可以使用
有关:
- 如何grep同一行上存在的两个单词?
- 检查文件中是否存在多个字符串或正则表达式
- 如何使用多个AND模式运行grep?并立即匹配文件中的所有模式
对于OR操作,请参阅:
- 如何使用具有管道字符的图案grep多个图案?
- Grep:如何添加"OR"条件?
将要grep的字符串放入文件中
1 2 3 | echo who > find.txt echo Roger >> find.txt echo [44][0-9]{9,} >> find.txt |
然后使用-f搜索
1 | grep -f find.txt BIG_FILE_TO_SEARCH.txt |
我经常遇到和你一样的问题,我刚写了一段脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | function m() { # m means 'multi pattern grep' function _usage() { echo"usage: COMMAND [-inH] -p<pattern1> -p<pattern2> <filename>" echo"-i : ignore case" echo"-n : show line number" echo"-H : show filename" echo"-h : show header" echo"-p : specify pattern" } declare -a patterns # it is important to declare OPTIND as local local ignorecase_flag filename linum header_flag colon result OPTIND while getopts"iHhnp:" opt; do case $opt in i) ignorecase_flag=true ;; H) filename="FILENAME," ;; n) linum="NR," ;; p) patterns+=("$OPTARG" ) ;; h) header_flag=true ;; \?) _usage return ;; esac done if [[ -n $filename || -n $linum ]]; then colon="":"," fi shift $(( $OPTIND - 1 )) if [[ $ignorecase_flag == true ]]; then for s in"${patterns[@]}"; do result+=" && s~/${s,,}/" done result=${result# && } result="{s=tolower(\$0)} $result" else for s in"${patterns[@]}"; do result="$result && /$s/" done result=${result# && } fi result+=" { print"$filename$linum$colon"\$0 }" if [[ ! -t 0 ]]; then # pipe case cat - | awk"${result}" else for f in"$@"; do [[ $header_flag == true ]] && echo"########## $f ##########" awk"${result}" $f done fi } |
用法:
1 2 | echo"a b c" | m -p A echo"a b c" | m -i -p A # a b c |
如果你愿意,可以把它放在.bashrc中。
用于多行匹配:
1 2 3 4 | echo -e"test1 test2 test3" |tr -d ' ' |grep"test1.*test3" |
要么
1 2 3 4 5 | echo -e"test1 test5 test3">tst.txt cat tst.txt |tr -d ' ' |grep"test1.*test3\|test3.*test1" |
我们只需要删除换行符就行了!
你应该像这样
1 | $ grep 'string1' file | grep 'string2' |
以下是使用
1 | rg -N '(?P<p1>.*string1.*)(?P<p2>.*string2.*)' file.txt |
它是最快的grepping工具之一,因为它建立在Rust的正则表达式引擎之上,它使用有限自动机,SIMD和积极的文字优化来快速搜索。
使用它,尤其是当您处理大数据时。
另请参阅GH-875的相关功能请求。