Linux命令:如何仅查找文本文件?


100

经过Google的几次搜索后,我想到的是:

find my_folder -type f -exec grep -l "needle text" {} \; -exec file {} \; | grep text

这非常不方便,并且会输出不需要的文本,例如mime类型信息。有更好的解决方案吗?我在同一文件夹中有很多图像和其他二进制文件,并且有很多文本文件需要搜索。

Answers:


184

我知道这是一个旧线程,但是我偶然发现了它,并认为我会分享我的方法,我发现这是一种非常快速的方法,可find用于仅查找非二进制文件:

find . -type f -exec grep -Iq . {} \; -print

-Igrep 的选项告诉它立即忽略二进制文件,而.连同的选项-q会使它立即与文本文件匹配,因此运行非常快。如果您担心空格,可以将其更改-print-print0用于管道到xargs -0或之类的东西(感谢小费,@ lucas.werkmeister!)

同样,仅对于某些BSD版本(find例如OS X)而言,第一个点才是必需的,但是如果您希望始终将其放置在别名或其他内容中,那么仅将其始终存在并不会带来任何伤害。

编辑:正如@ruslan正确指出的那样,-and可以隐式地将其省略。


16
在Mac OS X上,我需要将其更改为find . -type f -exec grep -Il "" {} \;
亚历克·雅各布森

3
这比peoro的回答要好,因为1.它实际上回答了问题2.它不会产生误报3.它的性能更高
user123444555621 2014年

3
您还可以使用find -type f -exec grep -Iq . {} \; -and -printwhich将文件保留在其中的优点find;您可以-print-exec只为文本文件运行的另一个替换。(如果让您grep打印文件名,则将无法使用换行符来区分文件名。)
Lucas Werkmeister 2015年

1
@ NathanS.Watson-Haigh不应该,因为它应该立即匹配文本文件。您有可以共享的特定用例吗?
crudcore

2
find . -type f -exec grep -Il . {} +快得多。缺点是它不能-exec像@ lucas.werkmeister所建议的那样被其他人扩展
Henning


10

为什么不方便?如果您需要经常使用它,并且不想每次都键入它,只需为其定义一个bash函数:

function findTextInAsciiFiles {
    # usage: findTextInAsciiFiles DIRECTORY NEEDLE_TEXT
    find "$1" -type f -exec grep -l "$2" {} \; -exec file {} \; | grep text
}

把它放在你的.bashrc然后运行:

findTextInAsciiFiles your_folder "needle text"

无论你什么时候想要。


编辑以反映OP的编辑:

如果您想删除mime信息,则可以在筛选出mime信息的管道中再添加一个阶段。这应该做的伎俩,通过采取只什么来之前:cut -d':' -f1

function findTextInAsciiFiles {
    # usage: findTextInAsciiFiles DIRECTORY NEEDLE_TEXT
    find "$1" -type f -exec grep -l "$2" {} \; -exec file {} \; | grep text | cut -d ':' -f1
}

我不确定“ grep文本”是否足够准确以获取所有文本文件-我的意思是,是否有任何文本文件类型的mime类型描述字符串中都没有“ text”?
datasn.io 2011年

@ kavoir.com:是的。摘自file手册:“用户依赖于知道目录中所有可读文件都印有'文本'一词。”
peoro 2011年

2
在grepping之前搜索文本文件,而不是grepping然后过滤掉文本文件,会不会更聪明?
用户未知

/proc/meminfo/proc/cpuinfo等是文本文件,但file /proc/meminfo/proc/meminfo: empty。我想知道是否除了“文本”之外还应该测试“空”,但是不确定是否其他类型也可以报告“空”。
TimoKähkönen2013年

“为什么不方便?” -“输出不需要的文本”。这个答案不能解决问题。
user123444555621 2014年

4
find . -type f -print0 | xargs -0 file | grep -P text | cut -d: -f1 | xargs grep -Pil "search"

不幸的是,这不能节省空间。将其放入bash脚本会使它变得更容易。

这是空间安全的:

#!/bin/bash
#if [ ! "$1" ] ; then
    echo "Usage: $0 <search>";
    exit
fi

find . -type f -print0 \
  | xargs -0 file \
  | grep -P text \
  | cut -d: -f1 \
  | xargs -i% grep -Pil "$1" "%"

2
脚本中有两个问题:1.如果二进制文件被命名text.bin怎么办?2.如果文件名包含一个字符:怎么办?
thkala 2011年

3

另一种方法是:

# find . |xargs file {} \; |grep "ASCII text"

如果您也想要空文件:

#  find . |xargs file {} \; |egrep "ASCII text|empty"

2

这个怎么样:

$ grep -rl "needle text" my_folder | tr '\n' '\0' | xargs -r -0 file | grep -e ':[^:]*text[^:]*$' | grep -v -e 'executable'

如果您想要不带文件类型的文件名,只需添加最终sed过滤器即可。

$ grep -rl "needle text" my_folder | tr '\n' '\0' | xargs -r -0 file | grep -e ':[^:]*text[^:]*$' | grep -v -e 'executable' | sed 's|:[^:]*$||'

您可以通过-e 'type'在最后一个grep命令中添加更多选项来过滤掉不需要的文件类型。

编辑:

如果您的xargs版本支持该-d选项,则上面的命令将变得更简单:

$ grep -rl "needle text" my_folder | xargs -d '\n' -r file | grep -e ':[^:]*text[^:]*$' | grep -v -e 'executable' | sed 's|:[^:]*$||'

愚蠢的我。没注意到递归grep。据我了解,尽管在许多应用程序中有一定的局限性,但它实际上相当快。为您+1。
2011年

2

这是我的做法...

1。编写一个小脚本来测试文件是否为纯文本istext:

#!/bin/bash
[[ "$(file -bi $1)" == *"file"* ]]

2。像以前一样使用find

find . -type f -exec istext {} \; -exec grep -nHi mystring {} \;

我猜你的意思是== *"text"* ]]
用户未知

您可以使用匹配运算符`=〜“ text”]]`。
用户未知

2

我对组织的回答有两个问题:

  • 它仅列出文本文件。它实际上并没有按要求搜索它们。要实际搜索,请使用

    find . -type f -exec grep -Iq . {} \; -and -print0 | xargs -0 grep "needle text"
    
  • 它为每个文件生成一个grep进程,这非常慢。那么一个更好的解决方案是

    find . -type f -print0 | xargs -0 grep -IZl . | xargs -0 grep "needle text"
    

    或简单地

    find . -type f -print0 | xargs -0 grep -I "needle text"
    

    与上述解决方案(2.5GB数据/ 7700文件)的4s相比,这仅需要0.2s,即20倍的速度

同样,没有人引用ag,Silver Searcherack- grep¸作为替代方案。如果可以使用以下方法之一,则它们是更好的选择:

ag -t "needle text"    # Much faster than ack
ack -t "needle text"   # or ack-grep

最后,请注意误报(二进制文件作为文本文件)。我已经使用grep / ag / ack进行了误报,因此最好在编辑文件之前先列出匹配的文件。


1

尽管这是一个古老的问题,但我认为此信息将增加此处答案的质量。

当忽略设置了可执行位的文件时,我只使用以下命令:

find . ! -perm -111

为了防止递归进入其他目录:

find . -maxdepth 1 ! -perm -111

不需要管道来混合大量命令,只需强大的普通查找命令即可。

  • 免责声明:这不是确切什么任择议定书要求,因为它不检查,如果该文件是二进制或没有。例如,它将过滤掉bash脚本文件,这些文件本身就是文本,但是具有可执行位set

就是说,我希望这对任何人都有用。


0

我这样做的方法是:1)由于要搜索的文件太多(〜30k),我每天使用以下命令生成文本文件列表以供crontab使用:

find /to/src/folder -type f -exec file {} \; | grep text | cut -d: -f1 > ~/.src_list &

2)在.bashrc中创建一个函数:

findex() {
    cat ~/.src_list | xargs grep "$*" 2>/dev/null
}

然后,我可以使用以下命令进行搜索:

findex "needle text"

HTH :)


0

我更喜欢xargs

find . -type f | xargs grep -I "needle text"

如果文件名很奇怪,请使用-0选项进行查找:

find . -type f -print0 | xargs -0 grep -I "needle text"

0
  • bash示例:在所有text / ascii文件中的/ etc中搜索文本“ eth0”

grep eth0 $(查找/ etc / -type f -exec文件{} \; | egrep -i“ text | ascii” | cut -d':'-f1)


0

这是简化版,其中提供了扩展的解释,适用于像我这样的初学者,他们正在尝试学习如何在一行中放置多个命令。

如果您要逐步写出问题,它将看起来像这样:

// For every file in this directory
// Check the filetype
// If it's an ASCII file, then print out the filename

要做到这一点,我们可以使用三种UNIX命令:findfile,和grep

find 将检查目录中的每个文件。

file将给我们文件类型。就我们而言,我们正在寻找返回“ ASCII文本”

grep 将从以下输出中查找关键字“ ASCII” file

那么,如何将它们串联在一起?有多种方法可以执行此操作,但是我发现按照伪代码的顺序进行操作最有意义(尤其是对于像我这样的初学者)。

find ./ -exec file {} ";" | grep 'ASCII'

看起来很复杂,但是当我们分解它时还不错:

find ./=浏览该目录中的每个文件。该find命令会打印出与“表达式”匹配的任何文件的文件名,或路径之后的任何文件名(在我们的情况下为当前目录或./

要了解的最重要的事情是,第一位之后的所有内容都将被评估为True或False。如果为True,则将打印出文件名。如果不是,则命令继续。

-exec=该标志是find命令中的一个选项,它使我们可以将某些其他命令的结果用作搜索表达式。就像在函数内调用函数一样。

file {}=在中调用的命令find。该file命令返回一个字符串,告诉您文件的文件类型。通常,它看起来像这样:file mytextfile.txt。在我们的例子中,我们希望它使用find命令正在查看的任何文件,因此我们将花括号放在其中{}以充当空变量或参数。换句话说,我们只是要求系统为目录中的每个文件输出一个字符串。

";"=这是命令find末尾的标点符号,也是标点符号-exec。如果需要运行,请参见手册中的“查找”以获取更多说明man find

| grep 'ASCII'= |是管道。管道将左侧的所有内容作为输出,然后将其用作右侧的所有内容的输入。它获取find命令的输出(字符串是单个文件的文件类型),并对其进行测试以查看其是否包含string 'ASCII'。如果是,则返回true。

现在,find ./grep命令返回true 时,右边的表达式将返回true。瞧


0

如果您有兴趣使用令人敬畏的file实用程序并结合使用的功能,通过魔术字节查找任何文件类型find,这会派上用场:

$ # Let's make some test files
$ mkdir ASCII-finder
$ cd ASCII-finder
$ dd if=/dev/urandom of=binary.file bs=1M count=1
1+0 records in
1+0 records out
1048576 bytes (1.0 MB, 1.0 MiB) copied, 0.009023 s, 116 MB/s
$ file binary.file
binary.file: data
$ echo 123 > text.txt
$ # Let the magic begin
$ find -type f -print0 | \
    xargs -0 -I @@ bash -c 'file "$@" | grep ASCII &>/dev/null && echo "file is ASCII: $@"' -- @@

输出:

file is ASCII: ./text.txt

图例:$是交互式shell提示符,我们在其中输入命令

您可以在之后修改该部分&&以调用其他脚本或也进行内联一些其他操作,即,如果该文件包含给定的字符串,请整理整个文件或在其中寻找辅助字符串。

说明:

  • find 文件项
  • xargs每个项目作为一行输入到一个衬里bash 命令/脚本中
  • file通过魔术字节grep检查文件的类型,检查是否存在ASCII(如果存在),然后在&&执行下一条命令后检查。
  • find将结果null分开打印,这可以避免转义带有空格和元字符的文件名。
  • xargs,使用-0option,将其null分开读取,-I @@ 获取每条记录并用作bash脚本的位置参数/ args。
  • --for bash确保无论它后面是参数如何,即使它以-like 开头,-c否则也可以解释为bash选项

如果您需要查找ASCII以外的grep ASCII其他类型,只需将其替换为其他类型,例如grep "PDF document, version 1.4"


-1
find . -type f | xargs file | grep "ASCII text" | awk -F: '{print $1}'

使用find命令列出所有文件,使用file命令验证它们是否为文本(不是tar,key),最后使用awk命令过滤并打印结果。


-4

这个怎么样

 find . -type f|xargs grep "needle text"

不需要寻找"needle text"
peoro 2011年

@Navi:提供的示例OP仅查找包含"needl text"
以下内容的

3
@Navi:现在不再查找文本文件:如果"needle text"将找到包含二进制文件
peoro 2011年

我为什么还要听你的话?
Navi

1
@Navi:您的一线工具不检查文件类型,并且文件名中的空格也存在主要问题……
thkala 2011年
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.