在共享库搜索路径中查找目录:另一种解决方案?
Find a directory in shared library search path : Another solution?
九年前,有人问过这个问题:在共享库搜索路径中查找目录 (Find a directory in shared library search path)。
已使用以下方式给出答案:opendir()
然后 readdir()
然后 dlopen()
...
现在有没有更简单的方法,还是我仍然应该遵循这个 SMOP?
事实上,opendir()/readdir()/closedir() 基本上从来没有 是 POSIXy 系统中任何东西的推荐方式,例如 Linux 具有 glob()
、scandir()
和 nftw()
,因为 home-spun opendir()/readdir()/closedir() 几乎从不处理重命名文件或目录的情况,在扫描过程中删除、创建或移动;而 POSIX C 库函数应该可以优雅地处理这些问题。
opendir()/readdir()/closedir() 如此受推崇的唯一原因是它们是在 C 标准中定义的(相对于 POSIX),因此可以在非 POSIXy 系统也是如此。但是,在我看来,仅仅因为某些系统的 C 库有缺陷,并不是一次又一次重新发明一个坏轮子的好理由;我们已经有了更好的工具。
例如,假设您构建了一个 glob 模式数组(例如,"/usr/lib/myapp/plugins/*.so", "/home/username/.config/myapp/plugins/*.so", NULL
),并且您想要找到与这些模式匹配的文件。为此,您使用 glob()
。例如:
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <glob.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
int report_error(const char *path, int errnum)
{
fprintf(stderr, "%s: %s.\n", path, strerror(errnum));
return -1;
}
void report_glob_error(int result)
{
switch (result) {
case GLOB_NOSPACE: fprintf(stderr, "%s.\n", strerror(ENOMEM)); return;
case GLOB_ABORTED: fprintf(stderr, "%s.\n", strerror(EIO)); return;
case GLOB_NOMATCH: fprintf(stderr, "%s.\n", strerror(ENOENT)); return;
}
}
int main(int argc, char *argv[])
{
glob_t matches;
size_t i;
int arg, result;
if (argc < 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
const char *argv0 = (argc > 0) ? argv[0] : "(this)";
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv0);
fprintf(stderr, " %s PATTERN [ PATTERN ... ]\n", argv0);
fprintf(stderr, "\n");
return EXIT_FAILURE;
}
result = glob(argv[1], GLOB_ERR | GLOB_MARK, report_error, &matches);
if (result) {
report_glob_error(result);
return EXIT_FAILURE;
}
for (arg = 2; arg < argc; arg++) {
result = glob(argv[arg], GLOB_ERR | GLOB_MARK | GLOB_APPEND, report_error, &matches);
if (result) {
report_glob_error(result);
return EXIT_FAILURE;
}
}
printf("Found %zu matches:\n", matches.gl_pathc);
for (i = 0; i < matches.gl_pathc; i++) {
printf(" %s\n", matches.gl_pathv[i]);
}
globfree(&matches);
return EXIT_SUCCESS;
}
编译并 运行 以上内容,例如'/lib*/*/*.so'
作为参数。请记住将模式放在单引号中,否则 shell 会扩展它们。
如果您想要特定目录中的所有文件,或者需要更复杂的文件名过滤器(例如,替代 glob 模式;您可以使用 fnmatch()
根据 glob 模式检查名称),您可以使用scandir()
.
请注意,如果 glob 模式不够,您可以使用 POSIX 正则表达式,通过 regcomp()
/regexec()
/regfree()
.
关于使用 scandir()
的示例,我刚刚发布了一个 ,以回答类似的问题。
九年前,有人问过这个问题:在共享库搜索路径中查找目录 (Find a directory in shared library search path)。
已使用以下方式给出答案:opendir()
然后 readdir()
然后 dlopen()
...
现在有没有更简单的方法,还是我仍然应该遵循这个 SMOP?
事实上,opendir()/readdir()/closedir() 基本上从来没有 是 POSIXy 系统中任何东西的推荐方式,例如 Linux 具有 glob()
、scandir()
和 nftw()
,因为 home-spun opendir()/readdir()/closedir() 几乎从不处理重命名文件或目录的情况,在扫描过程中删除、创建或移动;而 POSIX C 库函数应该可以优雅地处理这些问题。
opendir()/readdir()/closedir() 如此受推崇的唯一原因是它们是在 C 标准中定义的(相对于 POSIX),因此可以在非 POSIXy 系统也是如此。但是,在我看来,仅仅因为某些系统的 C 库有缺陷,并不是一次又一次重新发明一个坏轮子的好理由;我们已经有了更好的工具。
例如,假设您构建了一个 glob 模式数组(例如,"/usr/lib/myapp/plugins/*.so", "/home/username/.config/myapp/plugins/*.so", NULL
),并且您想要找到与这些模式匹配的文件。为此,您使用 glob()
。例如:
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <glob.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
int report_error(const char *path, int errnum)
{
fprintf(stderr, "%s: %s.\n", path, strerror(errnum));
return -1;
}
void report_glob_error(int result)
{
switch (result) {
case GLOB_NOSPACE: fprintf(stderr, "%s.\n", strerror(ENOMEM)); return;
case GLOB_ABORTED: fprintf(stderr, "%s.\n", strerror(EIO)); return;
case GLOB_NOMATCH: fprintf(stderr, "%s.\n", strerror(ENOENT)); return;
}
}
int main(int argc, char *argv[])
{
glob_t matches;
size_t i;
int arg, result;
if (argc < 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
const char *argv0 = (argc > 0) ? argv[0] : "(this)";
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv0);
fprintf(stderr, " %s PATTERN [ PATTERN ... ]\n", argv0);
fprintf(stderr, "\n");
return EXIT_FAILURE;
}
result = glob(argv[1], GLOB_ERR | GLOB_MARK, report_error, &matches);
if (result) {
report_glob_error(result);
return EXIT_FAILURE;
}
for (arg = 2; arg < argc; arg++) {
result = glob(argv[arg], GLOB_ERR | GLOB_MARK | GLOB_APPEND, report_error, &matches);
if (result) {
report_glob_error(result);
return EXIT_FAILURE;
}
}
printf("Found %zu matches:\n", matches.gl_pathc);
for (i = 0; i < matches.gl_pathc; i++) {
printf(" %s\n", matches.gl_pathv[i]);
}
globfree(&matches);
return EXIT_SUCCESS;
}
编译并 运行 以上内容,例如'/lib*/*/*.so'
作为参数。请记住将模式放在单引号中,否则 shell 会扩展它们。
如果您想要特定目录中的所有文件,或者需要更复杂的文件名过滤器(例如,替代 glob 模式;您可以使用 fnmatch()
根据 glob 模式检查名称),您可以使用scandir()
.
请注意,如果 glob 模式不够,您可以使用 POSIX 正则表达式,通过 regcomp()
/regexec()
/regfree()
.
关于使用 scandir()
的示例,我刚刚发布了一个