【发布时间】:2011-06-13 15:15:27
【问题描述】:
在谷歌搜索了几次后,我想出的是:
find my_folder -type f -exec grep -l "needle text" {} \; -exec file {} \; | grep text
这很不方便,会输出不需要的文本,例如 mime 类型信息。有更好的解决方案吗?我在同一个文件夹中有很多图像和其他二进制文件,还有很多我需要搜索的文本文件。
【问题讨论】:
在谷歌搜索了几次后,我想出的是:
find my_folder -type f -exec grep -l "needle text" {} \; -exec file {} \; | grep text
这很不方便,会输出不需要的文本,例如 mime 类型信息。有更好的解决方案吗?我在同一个文件夹中有很多图像和其他二进制文件,还有很多我需要搜索的文本文件。
【问题讨论】:
我知道这是一个旧线程,但我偶然发现了它并想分享我的方法,我发现这是一种非常快速的方法,可以使用 find 仅查找非二进制文件:
find . -type f -exec grep -Iq . {} \; -print
grep 的-I 选项告诉它立即忽略二进制文件,. 选项连同-q 将使它立即匹配文本文件,因此运行速度非常快。如果您担心空格,可以将-print 更改为-print0 以通过管道连接到xargs -0 或其他内容(感谢@lucas.werkmeister 的提示!)
此外,第一个点仅对某些 BSD 版本的 find 是必需的,例如在 OS X 上,但如果您想将它放在别名或其他东西中,它不会伤害任何东西。
编辑:正如@ruslan 正确指出的那样,-and 可以省略,因为它是隐含的。
【讨论】:
find . -type f -exec grep -Il "" {} \;。
find -type f -exec grep -Iq . {} \; -and -print,它的好处是将文件保存在find;您可以将-print 替换为另一个仅针对文本文件运行的-exec。 (如果你让grep 打印文件名,你将无法区分文件名中带有换行符。)
find . -type f -exec grep -Il . {} + 更快。缺点是它不能像@lucas.werkmeister 建议的那样被另一个-exec 扩展
grep -rIl "needle text" my_folder
【讨论】:
-I 是救生员。
为什么不方便?如果您需要经常使用它,并且不想每次都键入它,只需为其定义一个 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"
随时随地。
EDIT 以反映 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
}
【讨论】:
file 手册:“用户依赖于知道目录中的所有可读文件都打印了‘text’这个词。”
/proc/meminfo、/proc/cpuinfo 等是文本文件,但file /proc/meminfo 表示/proc/meminfo: empty。我想知道除了“文本”之外是否应该测试“空”,但不确定其他类型是否也可以报告“空”。
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" "%"
【讨论】:
text.bin 怎么办? 2.如果文件名包含:怎么办?
另一种方法:
# find . |xargs file {} \; |grep "ASCII text"
如果你也想要空文件:
# find . |xargs file {} \; |egrep "ASCII text|empty"
【讨论】:
这个怎么样:
$ 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|:[^:]*$||'
您可以通过在最后一个grep 命令中添加更多-e 'type' 选项来过滤掉不需要的文件类型。
编辑:
如果你的xargs 版本支持-d 选项,上面的命令就变得更简单了:
$ grep -rl "needle text" my_folder | xargs -d '\n' -r file | grep -e ':[^:]*text[^:]*$' | grep -v -e 'executable' | sed 's|:[^:]*$||'
【讨论】:
这就是我的做法......
1 .制作一个小脚本来测试文件是否为纯文本 文本:
#!/bin/bash
[[ "$(file -bi $1)" == *"file"* ]]
2 。像以前一样使用查找
find . -type f -exec istext {} \; -exec grep -nHi mystring {} \;
【讨论】:
== *"text"* ]]?
我对 histumness 的回答有两个问题:
它只列出文本文件。它实际上并没有将它们搜索为 请求。要实际搜索,请使用
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 个文件)相比,这只需要 0.2 秒,即 快 20 倍。
此外,没有人引用 ag, the Silver Searcher 或 ack-grep¸ 作为替代方案。如果其中之一可用,它们是更好的选择:
ag -t "needle text" # Much faster than ack
ack -t "needle text" # or ack-grep
最后一点,谨防误报(将二进制文件视为文本文件)。我已经使用 grep/ag/ack 误报了,所以最好在编辑文件之前先列出匹配的文件。
【讨论】:
对于像我这样正在尝试学习如何将多个命令放在一行中的初学者来说,这是一个带有扩展解释的简化版本。
如果你要分步写出问题,它应该是这样的:
// For every file in this directory
// Check the filetype
// If it's an ASCII file, then print out the filename
为此,我们可以使用三个 UNIX 命令:find、file 和 grep。
find 将检查目录中的每个文件。
file 会给我们文件类型。在我们的例子中,我们正在寻找“ASCII 文本”的返回
grep 将在file 的输出中查找关键字“ASCII”
那么我们怎样才能将它们串在一行中呢?有多种方法可以做到这一点,但我发现按照我们的伪代码的顺序来做最有意义(尤其是对于像我这样的初学者)。
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 命令的输出(一个字符串,它是单个文件的文件类型)并测试它是否包含字符串'ASCII'。如果是,则返回 true。
现在,find ./ 右侧的表达式将在 grep 命令返回 true 时返回 true。瞧。
【讨论】:
虽然这是一个老问题,但我认为下面的信息将增加这里答案的质量。
当忽略设置了可执行位的文件时,我只使用这个命令:
find . ! -perm -111
为了防止它递归进入其他目录:
find . -maxdepth 1 ! -perm -111
pipes 不需要混合很多命令,只需强大的普通 find 命令即可。
也就是说,我希望这对任何人都有用。
【讨论】:
我是这样做的: 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:)
【讨论】:
我更喜欢 xargs
find . -type f | xargs grep -I "needle text"
如果您的文件名很奇怪,请使用 -0 选项查找:
find . -type f -print0 | xargs -0 grep -I "needle text"
【讨论】:
grep eth0 $(find /etc/ -type f -exec file {} \; | egrep -i "text|ascii" | cut -d ':' -f1)
【讨论】:
如果您有兴趣使用强大的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 ,使用 -0 选项,读取它们 null 分隔,-I @@
获取每条记录并用作 bash 的位置参数/args
脚本。-- for bash 确保它之后的任何内容都是一个论点,甚至
如果它以- 开头,例如-c,否则可能会被解释
作为 bash 选项如果您需要查找 ASCII 以外的类型,只需将 grep ASCII 替换为其他类型,例如 grep "PDF document, version 1.4"
【讨论】:
find . -type f | xargs file | grep "ASCII text" | awk -F: '{print $1}'
使用 find 命令列出所有文件,使用 file 命令验证它们是文本(不是 tar,key),最后使用 awk 命令过滤并打印结果。
【讨论】:
这个怎么样
find . -type f|xargs grep "needle text"
【讨论】:
"needle text"
"needl text" 的文件
"needle text",它将被找到