Linux command: How to 'find' only text files?

After a few searches from Google, what I come up with is:

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

which is very unhandy and outputs unneeded texts such as mime type information. Any better solutions? I have lots of images and other binary files in the same folder with a lot of text files that I need to search through.

133329 次浏览

这个怎么样

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

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

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

put it in your .bashrc and then just run:

findTextInAsciiFiles your_folder "needle text"

whenever you want.


编辑 以反映 OP 的编辑:

如果你想删除哑剧信息,你可以在管道中增加一个阶段,过滤掉哑剧信息。这应该可以解决问题,因为它只取在 :: 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 -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|:[^:]*$||'

You can filter-out unneeded file types by adding more -e 'type' options to the last grep command.

编辑:

If your xargs version supports the -d option, the commands above become simpler:

$ grep -rl "needle text" my_folder | xargs -d '\n' -r file | grep -e ':[^:]*text[^:]*$' | grep -v -e 'executable' | sed 's|:[^:]*$||'
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" "%"

我是这么做的。

1. 创建一个小脚本来测试文件是否为纯文本 返回文章页面

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

2. 像以前一样使用 find

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

基于 这个所以问题:

grep -rIl "needle text" my_folder

我知道这是一个老线程,但我偶然发现它,并认为我应该分享我的方法,我已经发现是一个非常快的方法,使用 find只找到非二进制文件:

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

Grep 的 -I选项告诉它立即忽略二进制文件,而 .选项和 -q选项将使它立即匹配文本文件,因此速度非常快。如果你关心空间,你可以把 -print改成 -print0,以便管道连接到 xargs -0或者其他什么东西上(谢谢你的提示,@lucas)。沃克迈斯特!)

Also the first dot is only necessary for certain BSD versions of find such as on OS X, but it doesn't hurt anything just having it there all the time if you want to put this in an alias or something.

编辑 : 正如@ruslan 正确指出的那样,-and可以省略,因为它是隐含的。

我是这么做的: 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"

)

我更喜欢 Xargs

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

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

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

我对历史的回答有两个问题:

  • 它只列出文本文件。它实际上不搜索它们为 要实际搜索,请使用

    find . -type f -exec grep -Iq . {} \; -and -print0 | xargs -0 grep "needle text"
    
  • It spawns a grep process for every file, which is very slow. A better solution is then

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

    或者干脆

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

    对于以上解决方案(2.5 GB 数据/7700个文件) ,即 快20倍,这只需要0.2秒,而4s 只需要0.2秒。

此外,没有人引用 银色搜索者Ak-grep作为替代品。如果其中之一是可用的,他们是更好的替代品:

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

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

  • Bash 示例在/etc 中搜索所有 text/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会给我们文件类型。在我们的例子中,我们寻找返回的‘ ASCII 文本’

grep will look for the keyword 'ASCII' in the output from file

So how can we string these together in a single line? There are multiple ways to do it, but I find that doing it in order of our pseudo-code makes the most sense (especially to a beginner like me).

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

看起来很复杂,但分析起来还不错:

查看此目录中的每个文件。find命令输出任何与“表达式”匹配的文件的文件名,或者路径后面的任何文件,在我们的例子中是工作目录或者 ./

最重要的是要明白,在第一个位之后的所有内容都将被评估为 True 或 False。如果为 True,文件名将被打印出来。如果没有,则命令继续执行。

这个标志是 find 命令中的一个选项,它允许我们使用其他命令的结果作为搜索表达式。这就像在函数中调用函数一样。

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

";" = 这是 find所要求的,并且是 -exec命令末尾的标点符号。如果您需要通过运行 man find获得更多解释,请参阅“查找”手册。

| grep 'ASCII' = |是一根管子。管道把左边的输出作为右边的输入。它获取 find命令的输出(一个字符串,是单个文件的文件类型)并测试它是否包含字符串 'ASCII'。如果是,则返回 true。

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

Although it is an old question, I think this info bellow will add to the quality of the answers here.

当忽略文件 with the executable bit集时,我只需使用以下命令:

find . ! -perm -111

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

find . -maxdepth 1 ! -perm -111

不需要 管道混合许多命令,只需要强大的普通 find命令即可。

  • 免责声明: OP 要求的不是 没错,因为它不检查文件是否是 二进制。它将,例如,过滤出 Bash 脚本文件,这是 短信本身,但有 可执行位集可执行位集

That said, I hope this is useful to anyone.

另一种方法是:

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

如果你也想要空文件:

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

如果你有兴趣找到任何文件类型的魔术字节使用令人敬畏的 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 提示符,我们可以在其中输入命令

您可以在 &&之后修改这个部分来调用其他脚本,或者也可以内联地执行其他操作,例如,如果该文件包含给定的字符串,那么可以对整个文件执行 cat 命令,或者在其中查找辅助字符串。

Explanation:

  • find文件项
  • Make xargs feed each item as a line into one liner bash 命令/脚本
  • file通过神奇字节检查文件类型,grep检查 ASCII 如果存在,则在 &&之后执行下一个命令。
  • find打印结果 null分离,这是很好的逃避 包含空格和元字符的文件名。
  • xargs,使用 -0选项,读取它们分开的 null-I @@ 接受每条记录并将其作为 bash 的位置参数/args 剧本。
  • 对于 bash--确保后面的任何内容都是一个参数 如果它像 -c一样以 -开头,这可能会被解释为 作为 bash 选项

If you need to find types other than ASCII, simply replace grep ASCII with other type, like grep "PDF document, version 1.4"

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

Use find command to list all files, use file command to verify they are text (not tar,key), finally use awk command to filter and print the result.