本文介绍了如何仅在C中列出一级目录?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在终端中,我可以呼叫ls -d */.现在,我想要一个 c 的问题来为我完成此任务,就像这样:

In a terminal I can call ls -d */. Now I want a c program to do that for me, like this:

#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所有内容.但是,当我尝试时:

This will ls -l everything. However, when I am trying:

char *args[] = { "/bin/ls", "-d", "*/",  NULL };

我会收到一个运行时错误:

I will get a runtime error:

推荐答案

不幸的是,所有基于shell扩展的解决方案都受到最大命令行长度的限制.哪个有所不同(运行true | xargs --show-limits进行查找);在我的系统上,它约为2兆字节.是的,许多人会争辩说,这已经足够了-比尔·盖茨(Bill Gates)一次拥有640 KB.

Unfortunately, all solutions based on shell expansion are limited by the maximum command line length. Which varies (run true | xargs --show-limits to find out); on my system, it is about two megabytes. Yes, many will argue that it suffices -- as did Bill Gates on 640 kilobytes, once.

(在非共享文件系统上运行某些并行模拟时,在收集阶段,我有时确实在同一目录中有成千上万个文件.是的,我可以做不同的事情,但这恰好是最简单的方法,最强大的数据收集方式.实际上,很少有POSIX实用程序足以愚蠢地假设"X对每个人都足够".)

(When running certain parallel simulations on non-shared filesystems, I do occasionally have tens of thousands of files in the same directory, during the collection phase. Yes, I could do that differently, but that happens to be the easiest and most robust way to collect the data. Very few POSIX utilities are actually silly enough to assume "X is sufficient for everybody".)

幸运的是,有几种解决方案.一种是改为使用find:

Fortunately, there are several solutions. One is to use find instead:

system("/usr/bin/find . -mindepth 1 -maxdepth 1 -type d");

您还可以根据需要设置输出的格式,而不取决于语言环境:

You can also format the output as you wish, not depending on locale:

system("/usr/bin/find . -mindepth 1 -maxdepth 1 -type d -printf '%p\n'");

如果要对输出进行排序,请使用\0作为分隔符(因为文件名允许包含换行符),对于sort-t=也要使用\0作为分隔符. tr将为您将它们转换为换行符:

If you want to sort the output, use \0 as the separator (since filenames are allowed to contain newlines), and -t= for sort to use \0 as the separator, too. tr will convert them to newlines for you:

system("/usr/bin/find . -mindepth 1 -maxdepth 1 -type d -printf '%p\0' | sort -t= | tr -s '\0' '\n'");

如果要在数组中使用名称,请使用 glob() 函数代替.

If you want the names in an array, use glob() function instead.

最后,就像我不时地竖琴一样,可以使用POSIX nftw() 函数在内部实现此功能:

Finally, as I like to harp every now and then, one can use the POSIX nftw() function to implement this internally:

#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()调用以使用上述内容显然类似于

and the nftw() call to use the above is obviously something like

if (nftw(".", myfunc, NUM_FDS, FTW_ACTIONRETVAL)) {
    /* An error occurred. */
}

使用nftw()的唯一问题" 是选择功能可以使用的大量文件描述符(NUM_FDS). POSIX说一个进程必须始终能够至少有20个打开文件描述符.如果我们减去标准的(输入,输出和错误),则剩下的是17.不过,上面的值不太可能使用超过3.

The only "issue" in using nftw() is to choose a good number of file descriptors the function may use (NUM_FDS). POSIX says a process must always be able to have at least 20 open file descriptors. If we subtract the standard ones (input, output, and error), that leaves 17. The above is unlikely to use more than 3, though.

您可以使用 sysconf(_SC_OPEN_MAX) 找到实际限制,然后减去您的进程可能同时使用的描述符数量.在当前的Linux系统中,每个进程通常限制为1024.

You can find the actual limit using sysconf(_SC_OPEN_MAX), and subtracting the number of descriptors your process may use at the same time. In current Linux systems, it is typically limited to 1024 per process.

好处是,只要该数字至少为4或5左右,它只会影响性能:它仅确定nftw()在目录树结构中可以使用的深度,然后才能使用变通办法

The good thing is, as long as that number is at least 4 or 5 or so, it only affects the performance: it just determines how deep nftw() can go in the directory tree structure, before it has to use workarounds.

如果要创建包含很多子目录的测试目录,请使用类似以下Bash的内容:

If you want to create a test directory with lots of subdirectories, use something like the following 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

在我的系统上,运行

ls -d */

该目录中的

会产生bash: /bin/ls: Argument list too long错误,而find命令和基于nftw()的程序都可以正常运行.

in that directory yields bash: /bin/ls: Argument list too long error, while the find command and the nftw() based program all run just fine.

出于同样的原因,您也无法使用rmdir directory-*/删除目录.使用

You also cannot remove the directories using rmdir directory-*/ for the same reason. Use

find . -name 'directory-*' -type d -print0 | xargs -r0 rmdir

相反.或者只是删除整个目录和子目录,

instead. Or just remove the entire directory and subdirectories,

cd ..
rm -rf lots-of-subdirs

这篇关于如何仅在C中列出一级目录?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-04 20:31