grep在文件中的不同行上有多个字符串(即整个文件,不是基于行的搜索)?


85

我希望到grep包含文件的话DanskSvenska或者 Norsk任何线,以可用的返回码(因为我真的只喜欢有这些字符串包含了信息,我的一行又进了一步,然后这一点)。

我有很多这样的文件,其中有行:

Disc Title: unknown
Title: 01, Length: 01:33:37.000 Chapters: 33, Cells: 31, Audio streams: 04, Subpictures: 20
        Subtitle: 01, Language: ar - Arabic, Content: Undefined, Stream id: 0x20, 
        Subtitle: 02, Language: bg - Bulgarian, Content: Undefined, Stream id: 0x21, 
        Subtitle: 03, Language: cs - Czech, Content: Undefined, Stream id: 0x22, 
        Subtitle: 04, Language: da - Dansk, Content: Undefined, Stream id: 0x23, 
        Subtitle: 05, Language: de - Deutsch, Content: Undefined, Stream id: 0x24, 
(...)

这是我想要的伪代码:

for all files in directory;
 if file contains "Dansk" AND "Norsk" AND "Svenska" then
 then echo the filename
end

做这个的最好方式是什么?可以一行完成吗?

Answers:


89

您可以使用:

grep -l Dansk * | xargs grep -l Norsk | xargs grep -l Svenska

如果还要在隐藏文件中查找:

grep -l Dansk .* | xargs grep -l Norsk | xargs grep -l Svenska

聪明的解决方案;要注意的一件事(通常来说;与OP的要求无关)是即使在(概念上)失败的情况下,总体退出代码也将为0。因此,如果您对确定失败与成功感兴趣,则必须检查stdout输出是否为空,或者采用@EddSteel的方法。
mklement0 2012年

@mklement:在Bash中,该PIPESTATUS数组包含管道成员的退出值。
暂停,直到另行通知。

@DennisWilliamson很高兴知道,谢谢。另一个选项是pipefail(暂时)打开shell选项:shopt -so pipefail
mklement0

4
您可能要使用grep -Z并且xargs -0文件名是否可以包含空格。
Ben Challenor 2013年

1
如果您有许多文件,这可能会导致“参数列表过长”错误。
AnnanFay 2015年

23

仅使用bash和grep的另一种方法是:

对于单个文件“ test.txt”:

  grep -q Dansk test.txt && grep -q Norsk test.txt && grep -l Svenska test.txt

test.txt如果文件包含所有三个文件(以任意组合),则将打印。前两次不进行任何打印(-q),而后两次仅进行了打印,最后两次仅进行打印。

如果要对目录中的每个文件执行此操作:

   对于*中的f do grep -q丹麦语$ f && grep -q挪威语$ f && grep -l斯文斯卡$ f; 做完了

但随后无需执行grep 3次。
kurumi 2011年

1
我知道您可以将模式与-e结合使用,但是我看不到一种单独在grep中进行连接的方法。
Edd Steel'1

1
大; re for f ...:使用"$f"(双引号)而不是$f确保正确处理带有嵌入空格等的文件名。
mklement0 2012年

与@vmpstr相比,此方法的优势在于退出代码正确反映了是否找到了所有搜索词。
mklement0 2012年

19
grep –irl word1 * | grep –il word2 `cat -` | grep –il word3 `cat -`
  • -i 使搜索不区分大小写
  • -r 使文件搜索通过文件夹递归
  • -l 通过管道找到找到的单词的文件列表
  • cat - 使下一个grep浏览传递给它的文件列表。

1
这是最简单,最直接的答案,非常感谢!
majick

9

如何在不同的行上grep文件中的多个字符串(使用管道符号):

for file in *;do 
   test $(grep -E 'Dansk|Norsk|Svenska' $file | wc -l) -ge 3 && echo $file
done

笔记:

  1. 如果""对grep使用双引号,则必须像这样逃脱管道:\|搜索Dansk,Norsk和Svenska。

  2. 假设一行只有一种语言。

演练:http//www.cyberciti.biz/faq/howto-use-grep-command-in-linux-unix/


如果Dansk Norsk和Svenska都出现在同一行上,这不会失败吗?
vmpstr 2011年

是的,在这种情况下会失败。我假设这些语言每行出现一种。
Damodharan R 2011年

如果只有Norsk,但在三行中也将归档。
本杰明·

6

您可以使用ack轻松地完成此操作:

ack -l 'cats' | ack -xl 'dogs'
  • -l:返回文件列表
  • -x:从STDIN中获取文件(上一次搜索),仅搜索那些文件

而且,您可以一直进行管道传输,直到仅获得所需的文件为止。


当我尝试此操作时,它说Unknown option: x。是否有支持该x标志的ack特定版本?
哈桑

4
awk '/Dansk/{a=1}/Norsk/{b=1}/Svenska/{c=1}END{ if (a && b && c) print "0" }' 

然后可以使用shell捕获返回值

如果您有Ruby(1.9+)

ruby -0777 -ne 'print if /Dansk/ and /Norsk/ and /Svenka/' file

1
你的awk END子句中,你可能想:if (a && b && c) {exit 0} else {exit 1}或者更简洁exit !(a && b && c)
格伦·杰克曼

您的红宝石解决方案看起来不正确。只会打印包含所有搜索词的段落。问题是:文件(作为一个整体)是否包含所有单词,即使它们并非全部出现在同一段落中也是如此。
glenn jackman 2011年

谢谢。如果需要整个文件,则必须更改,然后必须使用-0777
kurumi 2011年

4

这将在多个文件中搜索多个单词:

egrep 'abc|xyz' file1 file2 ..filen 

2
除了查找同时具有两个字符串的文件之外,这还将查找单独包含“ abc”或“ xyz”的文件。我认为OP正在要求包含“ abc”和“ xyz”的文件。
克里斯·沃思

3

只是:

grep 'word1\|word2\|word3' *

看到这篇文章以获取更多信息


我会添加-l标志,但是除此之外,这个答案对我来说似乎是最直接的,除非我遗漏了一些东西。
xdhmoore

是的,因为您不处理多个管道和过滤器中的所有数据,所以效率更高
moshe beeri

3
该问题询问一个表达式,该表达式返回包含所有三个术语的文件。这将返回包含三个(而不是全部三个)中任何一个的行(而不是文件名)。
本杰明W.17年

2

这是glenn jackman和kurumi的答案的混合体,它允许使用任意数量的正则表达式,而不是任意数量的固定词或一组固定的正则表达式。

#!/usr/bin/awk -f
# by Dennis Williamson - 2011-01-25

BEGIN {
    for (i=ARGC-2; i>=1; i--) {
        patterns[ARGV[i]] = 0;
        delete ARGV[i];
    }
}

{
    for (p in patterns)
        if ($0 ~ p)
            matches[p] = 1
            # print    # the matching line could be printed
}

END {
    for (p in patterns) {
        if (matches[p] != 1)
            exit 1
    }
}

像这样运行它:

./multigrep.awk Dansk Norsk Svenska 'Language: .. - A.*c' dvdfile.dat

2

这对我来说很有效:

find . -path '*/.svn' -prune -o -type f -exec gawk '/Dansk/{a=1}/Norsk/{b=1}/Svenska/{c=1}END{ if (a && b && c) print FILENAME }' {} \;
./path/to/file1.sh
./another/path/to/file2.txt
./blah/foo.php

如果我只想找到这三个文件的.sh文件,那么我可以使用:

find . -path '*/.svn' -prune -o -type f -name "*.sh" -exec gawk '/Dansk/{a=1}/Norsk/{b=1}/Svenska/{c=1}END{ if (a && b && c) print FILENAME }' {} \;
./path/to/file1.sh

1

扩展@kurumi的awk答案,这是一个bash函数:

all_word_search() {
    gawk '
        BEGIN {
            for (i=ARGC-2; i>=1; i--) {
                search_terms[ARGV[i]] = 0;
                ARGV[i] = ARGV[i+1];
                delete ARGV[i+1];
            }
        }
        {
            for (i=1;i<=NF; i++) 
                if ($i in search_terms) 
                    search_terms[$1] = 1
        }
        END {
            for (word in search_terms) 
                if (search_terms[word] == 0) 
                    exit 1
        }
    ' "$@"
    return $?
}

用法:

if all_word_search Dansk Norsk Svenska filename; then
    echo "all words found"
else
    echo "not all words found"
fi

1

我做到了两步。在一个文件中列出一个csv文件列表在此页注释的帮助下,我执行了两个无脚本的步骤来获取所需的文件。只需输入终端:

$ find /csv/file/dir -name '*.csv' > csv_list.txt
$ grep -q Svenska `cat csv_list.txt` && grep -q Norsk `cat csv_list.txt` && grep -l Dansk `cat csv_list.txt`

它确实满足了我的需要-打印包含所有三个单词的文件名。

还请注意符号 `' "


1

如果只需要两个搜索词,那么可以说,最易读的方法是运行每个搜索并将结果相交:

 comm -12 <(grep -rl word1 . | sort) <(grep -rl word2 . | sort)

1

如果您安装了git

git grep -l --all-match --no-index -e Dansk -e Norsk -e Svenska

--no-index搜索当前目录中不受Git管理的文件。因此,此命令将在任何目录中运行,无论它是否是git存储库。


0

我今天遇到了这个问题,这里的所有单行代码都对我失败了,因为文件名中包含空格。

这是我想出的方法:

grep -ril <WORD1> | sed 's/.*/"&"/' | xargs grep -il <WORD2>
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.