我需要在某个目录及其所有子目录中找到包含自己名称的所有文本文件。我该怎么做呢? (最好没有 awk 命令)
答案1
为了最大程度地可移植并在文件名可能包含空格或来自 的其他字符时工作,并且在不处理内部引号的IFS
系统上,请使用find
{}
find -exec
结合和sh
和普通参数传递:
find DIRECTORY -type f -exec sh -c 'grep -lFe "$(basename "$1")" "$1"' sh {} ';'
find DIRECTORY -type f
递归枚举下所有普通文件DIRECTORY
。-exec ... ';'
为它找到的每个文件运行一个命令。它的核心是sh
通过 to 的命令{}
,其中:
- 使用以下命令运行标准 shell脚本
grep -lFe "$(basename "$1")" "$1"
每个匹配文件的 命令字符串,其中: - 并将两个参数传递给
sh
:“sh
”和{}
。sh
用于内联脚本$0
(正在运行的程序的名称,例如 shell 用于错误报告)。将替换完全由匹配的文件名find
组成的参数,因此脚本本身会获得一个参数,其完整文件路径可用作.{}
sh
$1
这适用于任何 POSIX 兼容系统。{}
在带引号的字符串内使用find -exec
具有实现定义的行为grep
,因此不可移植(尽管 GNU和大多数 BSD支持它)并且由于文件名被解释而很危险作为外壳代码。
当任意文件名可能包含空格、通配符或IFS
输入字段分隔符变量的值未知时,它们始终需要引用;否则它们将被分成多个单词并使程序以意想不到的方式运行。
更高效的是,您可以使用find -exec
with+
来运行尽可能少的 shell:
find DIRECTORY -type f -exec sh -c 'for x in "$@" ; do grep -lFe "$(basename "$x")" "$x" ; done' sh {} '+'
这仍然是可移植的,但为每次执行提供了许多文件路径sh
,因此它不会启动那么多的 shell。 shell程序里面有一个for
环形它会查看每个文件。如果这是要频繁运行的东西,那么这是比使用“ ;
”终止命令更好的选择。
答案2
find directoryname -type f -exec grep -l {} {} \;
这告诉find
我们搜索纯文件(即排除目录、设备、符号链接等),并使用grep
给定的参数执行每个找到的文件。-l
指示 grep 仅显示文件名,而不显示匹配的行。代表{}
文件名,\;
终止命令。
当然,您可能的意思是必须搜索文件名本身而不是路径。这意味着目录部分需要从第一部分中删除{}
。一种解决方案可能是:
find directoryname -type f -exec sh -c 'grep -l $(basename {}) {}' \;
$( .. )
现在,对于每个文件,都会启动一个 shell,因为必须完成参数替换。basename
删除任何前导目录部分。
注意需要使用单引号,否则 $( .. ) 部分将在您输入命令时计算,而不是在通过 find 启动 shell 时计算。
答案3
在 GNU 系统上,您可以执行以下操作:
find . -type f -printf '%f\0%p\0' | xargs -r0n2 grep -lFe
(-type f
是限制为常规的仅文件。-xtype f
如果您还想考虑常规文件的符号链接,请更改为)。
答案4
这对我有用:
find /path/ -type f -exec sh -c "grep -l \"\$(basename {})\" {}" \;
Explanation:
-type f
: 只查找文件sh -c
:为每个文件执行一个 shellgrep -l
: 只显示文件名\$(basename {})
: grep 获取基本名称