我想要一个命令行命令来搜索文件系统中的所有 shell 脚本中的特定单词,所以我在工作中询问并得到了以下解决方案:
grep word `find / -name \*.sh 2>/dev/null`
find / -name "*.sh" 2>/dev/null | xargs grep word
但是,我对命令行不太熟悉,因此这两种解决方案对我来说似乎都不透明。我更喜欢做类似的事情:
ls -r *.sh | cat | grep -H word
但似乎你无法将文件名通过管道传输到 cat (至少我认为这就是问题所在)。
最清晰的解决方案是什么?其次,最有效的解决方案是什么?
编辑:我需要知道在哪个文件中找到该单词,以便我可以修改脚本。
答案1
编辑:如果您有 GNU 实用程序,请参阅吉尔斯的回答grep
使用GNU 递归能力的方法比该find
方法简单得多。如果您只想显示文件名,您仍然需要添加-l
我在下面描述的选项。
用于grep -l word
仅打印包含匹配项的文件的名称。
如果您想.sh
从根目录开始查找文件系统中以 结尾的所有文件/
,那么这find
是最合适的工具。
最便携、最有效的建议是:
find / -type f -name '*.sh' -exec grep -l word {} + 2>/dev/null
这几乎是可读的,如果您了解每个组件背后的语义,那么解析起来并不困难。
find /
:find
从文件系统根目录开始运行,/
-type f
: 只匹配常规文件-name '*.sh'
: ...并且仅匹配名称以以下结尾的文件.sh
-exec ... {} +
...
:在组中的匹配文件上运行指定的命令,其中{}
替换为组中的文件名。这个想法是在系统()的限制内一次对尽可能多的文件运行该命令ARG_MAX
。该表单的效率{} +
来自于...
通过最大化传递给每次调用的文件数来最小化必须调用命令的次数...
。grep -l word {}
:其中{}
与{}
上面重复并被文件名替换。如前所述,grep -l
打印包含word
.2>/dev/null
:隐藏错误消息(从技术上讲,将标准错误重定向到黑洞/dev/null
)。这是出于美观和实际原因,因为运行find
可能/
会导致大量“权限被拒绝”消息,您可能不关心您无权读取的文件和您无权遍历的目录。
您在问题中收到和发布的建议存在一些问题。两个都
grep word `find / -name \*.sh 2>/dev/null
和
find / -name "*.sh" 2>/dev/null | xargs grep word
名称中含有空格的文件失败。最好避免将文件名完全放入命令替换中。第一个有可能遇到 ARG_MAX 限制的额外问题。第二个接近我的建议,但没有充分的理由在xargs
这里使用,更不用说安全和正确的使用xargs
需要牺牲一些仅 GNU 选项的可移植性 ( find -print0 | xargs -0
)。
答案2
答案3
grep
和的组合find
在很多情况下是ack
(betterthangrep.com):
ack [OPTION]... PATTERN [FILE]
对于您的示例,请考虑使用
ack --shell word /
笔记
ack
- 递归搜索(默认情况下),但是
- 忽略(默认)常见版本控制系统中的目录,例如
.git
,.hg
,.svn
, ... - 可以通过使用常见文件类型的过滤器轻松缩小结果范围(有关不同的文件名模式,请参见下文)
- 具有
grep
类似语法和相同/相似的参数,例如-i
“忽略大小写”等。 - 可能会
ack-grep
在你的系统上调用(在基于 Debian 的发行版上,如果我没记错的话)
文件名模式
该选项--shell
是缩写--type=shell
并包含多种文件类型:当前.sh .bash .csh .tcsh .ksh .zsh
根据
ack --help-types
如果您只想要.sh
文件,则必须定义(添加)您自己的类型sh
并使用此过滤器(--sh
),如下所示:
ack word --type-add=sh=.sh --sh /
这听起来有点复杂,但允许递归搜索.sh
下面的文件/
。对于本地搜索(不指定起始目录,例如\
)会更容易:
ack word *.sh