在终端我可以打电话给ls -d */。现在,我想要一个c程序为我做这件事,像这样:
ls -d */
#include <sys/types.h> #include <sys/wait.h> #include <stdio.h> #include <unistd.h> int main( void ) { int status; char *args[] = { "/bin/ls", "-l", NULL }; if ( fork() == 0 ) execv( args[0], args ); else wait( &status ); return 0; }
这将ls -l一切。但是,当我尝试:
ls -l
char *args[] = { "/bin/ls", "-d", "*/", NULL };
我会收到一个运行时错误:
ls:* /:没有这样的文件或目录
不幸的是,所有基于shell扩展的解决方案都受到最大命令行长度的限制。哪个有所不同(可以true | xargs --show- limits找出答案);在我的系统上,大约有2 MB。是的,许多人会争辩说它就足够了-一次比尔·盖茨就拥有640 KB的容量。
true | xargs --show- limits
(在非共享文件系统上运行某些并行模拟时,在收集阶段,我有时确实在同一目录中有成千上万个文件。是的,我可以做不同的事情,但这恰恰是最简单,最可靠的方法收集数据。实际上,几乎没有POSIX实用程序足以愚蠢地假设“ X对每个人都足够”。)
幸运的是,有几种解决方案。一种是改为使用find:
find
system("/usr/bin/find . -mindepth 1 -maxdepth 1 -type d");
您还可以根据需要设置输出的格式,而不取决于语言环境:
system("/usr/bin/find . -mindepth 1 -maxdepth 1 -type d -printf '%p\n'");
如果要排序的输出,使用\0作为分隔符(因为文件名被允许包含换行符),并-t=为sort使用\0作为分隔符,太。tr会为您将它们转换为换行符:
\0
-t=
sort
tr
system("/usr/bin/find . -mindepth 1 -maxdepth 1 -type d -printf '%p\0' | sort -t= | tr -s '\0' '\n'");
如果要在数组中使用名称,请改用glob()function。
glob()
最后,就像我不时地竖琴一样,可以使用POSIX nftw()函数在内部实现此功能:
nftw()
#define _GNU_SOURCE #include <stdio.h> #include <ftw.h> #define NUM_FDS 17 int myfunc(const char *path, const struct stat *fileinfo, int typeflag, struct FTW *ftwinfo) { const char *file = path + ftwinfo->base; const int depth = ftwinfo->level; /* We are only interested in first-level directories. Note that depth==0 is the directory itself specified as a parameter. */ if (depth != 1 || (typeflag != FTW_D && typeflag != FTW_DNR)) return 0; /* Don't list names starting with a . */ if (file[0] != '.') printf("%s/\n", path); /* Do not recurse. */ return FTW_SKIP_SUBTREE; }
和nftw()使用上面的电话显然是这样的
if (nftw(".", myfunc, NUM_FDS, FTW_ACTIONRETVAL)) { /* An error occurred. */ }
唯一的 “问题” 的使用nftw()是选择文件描述符的函数可以使用的一个好数字(NUM_FDS)。POSIX说,一个进程必须始终能够至少有20个打开文件描述符。如果我们减去标准的(输入,输出和错误),则剩下的是17。但是,上面的值不太可能使用超过3。
NUM_FDS
您可以使用找到实际限制sysconf(_SC_OPEN_MAX),然后减去您的进程可能同时使用的描述符数量。在当前的Linux系统中,每个进程通常限制为1024。
sysconf(_SC_OPEN_MAX)
好消息是,只要该数字至少为4或5,那么它只会影响性能:它仅决定nftw()必须使用变通办法之前目录树结构的深度。
如果要创建包含许多子目录的测试目录,请使用以下Bash之类的方法:
mkdir lots-of-subdirs cd lots-of-subdirs for ((i=0; i<100000; i++)); do mkdir directory-$i-has-a-long-name-since-command-line-length-is-limited ; done
在我的系统上,正在运行
在该目录中会产生bash: /bin/ls: Argument list too long错误,而find命令和nftw()基于程序都可以正常运行。
bash: /bin/ls: Argument list too long
同样,您也无法使用删除目录rmdir directory-*/。采用
rmdir directory-*/
find . -name 'directory-*' -type d -print0 | xargs -r0 rmdir
代替。或者只是删除整个目录和子目录,
cd .. rm -rf lots-of-subdirs