我有一个包含几个目录的项目(其中并非所有目录都是预先知道的)。我想要发出一个命令来查找所有包含源代码的目录。类似于 find . -name "*.cpp"
这将给我一个源码列表,而我只想要包含它们的目录列表。项目结构事先不知道,一些源代码可能存在于目录X中,而其他源代码可能存在于子目录X/Y中。哪个命令会打印出包含源代码的所有目录列表?
我有一个包含几个目录的项目(其中并非所有目录都是预先知道的)。我想要发出一个命令来查找所有包含源代码的目录。类似于 find . -name "*.cpp"
这将给我一个源码列表,而我只想要包含它们的目录列表。项目结构事先不知道,一些源代码可能存在于目录X中,而其他源代码可能存在于子目录X/Y中。哪个命令会打印出包含源代码的所有目录列表?
find . -name "*.cpp" -exec dirname {} \; | sort -u
find
或最新版本的BSD find
,并且(b)您有一个最新版本的dirname
(例如GNU coreutils 8.21或FreeBSD 10,但不包括OSX 10.10),那么为了提高效率,请使用以下方法(致谢:Jochen和mklement0):find . -name "*.cpp" -exec dirname {} + | sort -u
find . -name \*.cpp -exec dirname '{}' + | sort -u
- Jochendirname
处理多个参数?我的(Debian Stable)不支持。 - John1024dirname
的(GNU coreutils) 8.13
版本(例如,在Debian 3.2上)不支持多个参数,但是(GNU coreutils) 8.21
版本(例如,在Ubuntu 14.04和Fedora 20上)支持。同样,在BSD世界中,OSX 10.10版本不支持多个参数,而FreeBSD 10版本支持。 - mklement0+
选项和版本信息。 - John1024John1024的答案非常简洁明了,而且速度很快,如果你的版本的dirname
支持多个参数,并且可以使用-exec dirname {} +
调用它。
否则,使用-exec dirname {} \;
,每个输入文件名都会fork出一个子进程,这样会非常慢。
如果:
dirname
不支持多个参数4
或更高版本请考虑以下解决方案:
shopt -s globstar; printf '%s\n' ./**/*.cpp | sed 's|/[^/]*$||' | sort -u
shopt -s globstar
激活跨目录路径名扩展(globbing)的支持。./**/**.cpp
然后匹配当前目录子树中任何位置的.cpp
文件。
./
开头,因此下面的sed
命令也可以正确报告顶级目录本身,如果它包含匹配的文件。sed 's|/[^/]*$||'
实际上执行与dirname
相同的操作,但是在单个 sed
调用中对所有输入行进行操作。
sort -u
对结果进行排序,并仅输出唯一的目录名称。find . -name "*.cpp" | while read f; do dirname "$f" ; done | sort -u
find . -name '*.cpp' | sed -e 's/\/[^/]*$//' | sort | uniq
要查找非空目录:
$ find . \! -empty -type d
如果只想查找特定文件类型的目录,可以使用以下命令:
find . -name \*.cpp | while read line; do dirname "${line}" ; done | sort -u
此命令会查找所有 *.cpp 文件,并对每个文件名调用 dirname
。然后对结果进行排序并去重。使用 shell 内置命令可能有更快的方法,不需要为每个 *.cpp 文件生成新进程。但对于大多数项目来说,这可能并不重要。
find
中使用shell内置命令不是一个选项,但如果您使用的是bash 4+,则可以使用shopt -s globstar
和路径名扩展来实现更快的解决方案。 - mklement0你应该定义什么是源文件。
请注意,某些 C 或 C++ 文件是生成的(例如通过解析器生成器如bison或yacc
、由特定于项目的生成器等生成),而一些包含的 C 或 C++ 文件未命名为.h
或.cc
(请阅读有关X-macros的内容)。在GCC中,大量的文件是生成的(例如从*.md
机器描述文件生成的文件,这些是真正的源文件)
大多数大型软件项目(例如由许多百万行 C++ 或 C 代码组成的项目)都具有或正在使用某些 C 或 C++ 代码生成器。
在自由软件世界中,源代码只是开发人员正在使用的代码的首选形式。
请注意,源代码可能不会放在文件中;它可以放在数据库中,或者是堆镜像中,例如如果开发人员正在与特定程序交互以进行工作(请记住1980年代的Smalltalk机器,或INRIA在1980年的Mentor structured editor)。另一个例子是J.Pitrat的CAIA系统完全是自动生成的C代码。还请查看Scheme48。
也许(仅作为近似启发式方法),您应该将任何命名为.h
、.cc
、.cpp
、.cxx
或者可能包含GENERATED FILE
单词(通常在某些注释中)但不包含在内的.def
、.inc
、.tcc
文件视为C++源文件。
Makefile
、CMake*
、Makefile.am
和autoconf
等描述...)。 没有一种万无一失的方法来检测或猜测生成的C++文件,因此您将无法可靠地自动化检测它们。boot/
子目录,而MELT具有一个melt/generated/
目录(其中包含生成MELT的C++文件*.melt
源代码文件)以C++形式。
我建议使用项目版本控制存储库并获取那里的非空目录。具体细节取决于版本控制工具(例如git,或svn
,或hg
等)。您应该使用一些版本控制(或修订控制)工具。我推荐使用git