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

经过Google的几次search之后,我想到的是:

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

这是非常不方便的,并输出不需要的文本,如MIMEtypes信息。 有更好的解决scheme 我有很多的图像和其他二进制文件在同一个文件夹中有很多文本文件,我需要通过search。

我知道这是一个古老的线程,但我偶然发现它,并认为我会分享我的方法,我发现这是一个非常快速的方式来使用查找只发现非二进制文件:

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

grep的-I选项告诉它立即忽略二进制文件和. 选项以及-q将使其立即匹配文本文件,因此速度非常快。 如果你关心的是空间,你可以把-print-print0以便将其装入xargs -0或其他东西(感谢提示,@ lucas.werkmeister!)

另外第一个点只对某些BSD版本的find是必要的,比如在OS X上,但是如果你想把它放在一个别名或者别的什么地方,它不会伤害任何东西。

为什么不方便? 如果你需要经常使用它,而不想每次只input一个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信息,你可以添加一个进一步的阶段到pipe道,过滤出哑剧信息。 这应该做的伎俩,只采取什么之前:: 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 } 

基于这个SO问题 :

grep -rIl "needle text" my_folder

 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" "%" 

这个怎么样:

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

如果你想要的文件名没有文件types,只需添加一个最后的sedfilter。

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

您可以通过向最后的grep命令添加更多-e 'type'选项来过滤不需要的文件types。

编辑:

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

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

我是这样做的

1。 制作一个小脚本来testing一个文件是纯文本istext:

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

2。 像以前一样使用查找

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

我有两个问题与histumness'答案:

  • 它只列出文本文件。 它实际上并没有按要求search它们。 要真正search,使用

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

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

    上述解决scheme只需要0.2s(2.5GB数据/ 7700个文件),即20倍

此外,没有人引用ag,Silver Searcher或ack-grep作为替代品。 如果其中一个可用,他们是更好的select:

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

作为最后一点, 要小心误报 (二进制文件作为文本文件)。 我已经有了使用grep / ag / ack的误报,所以最好在编辑文件之前列出匹配的文件。

虽然这是一个老问题,但我认为这个信息会增加答案的质量。

忽略可执行位设置的文件时 ,我只使用这个命令:

 find . ! -perm -111 

为了防止它recursion地进入其他目录:

 find . -maxdepth 1 ! -perm -111 

不需要pipe道混合大量的命令,只需要强大的简单查找命令。

  • 免责声明:这不是OP所要求的,因为它不检查文件是否是二进制文件。 例如,它会过滤掉bash脚本文件,这些文件本身就是文本 ,但可执行位已设置

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

另一种做法是:

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

如果你也想要空文件:

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

我这样做:1)因为有太多的文件(〜30k)来search,我通过使用下面的命令每天生成文本文件列表通过crontab使用:

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

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

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

然后我可以使用下面的命令来进行search:

 findex "needle text" 

HTH 🙂

我更喜欢xargs

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

如果你的文件名奇怪的使用-0选项查找:

 find . -type f -print0 | xargs -0 grep -I "needle text" 
  • bash例子来在/ etc中清除所有文本/ ascii文件中的文本“eth0”

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

这里有一个简化的版本,为像我这样的初学者提供了扩展的解释,他们正试图学习如何将多个命令放在同一行中。

如果你要逐步写出这个问题,看起来像这样:

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

为此,我们可以使用三个UNIX命令: findfilegrep

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

file将给我们的文件types。 在我们的情况下,我们正在寻找“ASCII文本”

grep将在file的输出中查找关键字“ASCII”

那么我们怎么能把这些串在一起呢? 有很多种方法可以做到这一点,但是我发现按照我们的伪代码的顺序来做是最有意义的(对于像我这样的初学者来说尤其如此)。

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

看起来很复杂,但不是坏的,当我们分解:

find ./ =查看这个目录中的每个文件。 find命令打印出与“expression式”匹配的任何文件的文件名,或者path后面的任何文件,在我们的例子中是当前目录或者./

要理解的最重要的事情是,在第一点之后的所有东西都将被评估为“真”或“假”。 如果为True,文件名将被打印出来。 如果不是,则命令继续。

-exec =这个标志是find命令中的一个选项,它允许我们使用其他命令的结果作为searchexpression式。 这就像在一个函数中调用一个函数。

file {} =在find中调用的命令。 file命令返回一个string,告诉你文件的文件types。 定期,它会看起来像这样: file mytextfile.txt 。 在我们的例子中,我们希望它使用find命令查看的任何文件,所以我们把大括号{}作为一个空variables或参数。 换句话说,我们只是要求系统为目录中的每个文件输出一个string。

";" =这是find所要求的,是我们-exec命令结尾的标点符号。 如果您需要运行man find请参阅“find”手册以获取更多解释。

| grep 'ASCII' | grep 'ASCII' = | 是一个pipe道。 pipe道取左边的任何输出,并将其用作右边的任何input。 它使用find命令的输出(一个string是单个文件的文件types)并testing它是否包含string'ASCII' 。 如果是,则返回true。

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

这个怎么样

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