我有一个目录(例如abc/def/efg
),其中包含许多子目录(例如abc/def/efg/(1..300)
:)。所有这些子目录都有一个公共文件(例如)file.txt
。我想仅在其中搜索字符串file.txt
而不搜索其他文件。我该怎么做?
我使用过 grep -arin "pattern" *
,但是如果我们有许多子目录和文件,它就会非常慢。
答案1
在父目录中,您可以使用find
并grep
仅对那些文件运行:
find . -type f -iname "file.txt" -exec grep -Hi "pattern" '{}' +
答案2
您也可以使用 globstar。
使用创建grep
命令find
,如 Zanna 的回答中所述,是一种高度健壮、多功能且可移植的方法(另请参阅sududus 的回答)。 和muru 发布了一个使用选项grep
的极好方法--include
。但如果您只想使用命令grep
和 shell,还有另一种方法可以做到——你(们)能做到外壳本身执行必要的递归:
shopt -s globstar # you can skip this if you already have globstar turned on
grep -H 'pattern' **/file.txt
即使只找到一个匹配的文件,该-H
标志也会显示文件名。如果需要,您也可以将、和标志(来自您的示例)传递给。但使用此方法时不要传递或。它是grep
-a
-i
-n
grep
-r
-R
贝壳**
递归目录以扩展包含、 和 的glob 模式不是grep
。
这些指令特定于 Bash shell。Bash 是 Ubuntu(以及大多数其他 GNU/Linux 操作系统)中的默认用户 shell,因此如果您使用的是 Ubuntu 并且不知道您的 shell 是什么,那么它几乎肯定是 Bash。虽然流行的 shell 通常支持目录遍历**
glob,但它们的工作方式并不总是相同的。有关更多信息,请参阅斯蒂芬·查泽拉斯的很好的答案到ls * 、 ls ** 和 ls *** 的结果在Unix操作系统。
怎么运行的
打开全球星狂欢shell 选项匹配**
包含目录分隔符 ( /
) 的路径。因此它是一个目录递归 glob。具体来说,man bash
解释:
当。。。的时候全球星shell 选项已启用,并且在路径名扩展上下文中使用 *,则用作单个模式的两个相邻 * 将匹配所有文件以及零个或多个目录和子目录。如果后面跟着一个 /,则两个相邻 * 将仅匹配目录和子目录。
您应该对此小心谨慎,因为您可能会运行修改或删除远多于预期文件的命令,尤其是**
当您想写的时候却写了*
。 (此命令是安全的,它不会更改任何文件。)shopt -u globstar
将 globstar shell 选项关闭。
globstar 和 之间存在一些实际差异find
。
find
比 globstar 功能更强大。任何你能用 globstar 做的事情,你都能用这个find
命令做。我喜欢 globstar,有时它更方便,但 globstar 不是一个一般的替代find
。
上述方法不会查找名称以 开头的目录.
。有时您不想递归此类文件夹,但有时您想。
与普通的 glob 一样,shell 会构建所有匹配路径的列表,并将它们作为参数传递给命令 ( grep
),而不是 glob 本身。如果您调用的文件太多,file.txt
以至于生成的命令太长而无法执行,则上述方法将失败。实际上,您需要 (至少) 数千个这样的文件,但这种情况可能会发生。
所使用的方法find
不受此限制,因为:
扎娜的方式构建并运行
grep
可能带有许多路径参数的命令。但是,如果找到的文件多于单个路径中可以列出的文件数,则+
-terminated操作将使用部分路径运行该命令,然后使用更多路径再次运行该命令,依此类推。在对多个文件中的字符串进行 ing-exec
的情况下,这会产生正确的行为。grep
与此处介绍的 globstar 方法类似,这将打印所有匹配的行,并在每个行前面添加路径。
sududus 的方式
grep
对每个找到的文件分别运行file.txt
。如果文件很多,它可能比其他方法慢,但它确实有效。
获取颜色find
使用 globstar 的直接好处之一是,在 Ubuntu 上默认grep
会产生彩色输出。但是find
你也可以轻松获得它。
Ubuntu 中的用户帐户是通过别名这让人跑去grep
看看。这是grep --color=auto
alias grep
一件好事别名是只有当你交互发布它们时才会扩展,但这意味着如果你想用该标志find
调用,你必须明确地写出它。例如:grep
--color
find . -name file.txt -exec grep --color=auto -H 'pattern' {} +
答案3
你不需find
要这样做;grep
它可以自己完美地处理这个问题:
grep "pattern" . -airn --include="file.txt"
从man grep
:
--exclude=GLOB
Skip files whose base name matches GLOB (using wildcard
matching). A file-name glob can use *, ?, and [...] as
wildcards, and \ to quote a wildcard or backslash character
literally.
--exclude-from=FILE
Skip files whose base name matches any of the file-name globs
read from FILE (using wildcard matching as described under
--exclude).
--exclude-dir=DIR
Exclude directories matching the pattern DIR from recursive
searches.
--include=GLOB
Search only files whose base name matches GLOB (using wildcard
matching as described under --exclude).
答案4
需要指出的是,如果问题的条件可以采取文学性,则可以直接使用 grep:
grep 'pattern' abc/def/efg/*/file.txt
或者
grep 'pattern' abc/def/efg/{1..300}/file.txt