【问题标题】:How does my Linux C process know how many files were opened on the command line?我的 Linux C 进程如何知道在命令行上打开了多少文件?
【发布时间】:2020-05-04 21:42:37
【问题描述】:

当我在 Linux 下启动一个进程时,我可以传递多个输入和输出重定向。例如,如果我想要 14 个输出文件,我会这样做:

command >f1 3>f2 4>f3 5>f4 6>f5 7>f6 8>f7 9>f8 10>f9 11>f10 12>f11 13>f12 14>f13 15>f14

我的命令能否确切知道在命令行中传递了多少这样的文件?

我知道我总是可以添加一个命令行选项,例如--count 14。我希望我们不必这样做。

【问题讨论】:

  • 出于好奇,为什么不将它们作为常规命令行参数传入?
  • in c 我认为这些设置为文件描述符表中的文件描述符。 stackoverflow.com/questions/2423628/…
  • @LouFranco 那行不通。 stdio 中未引​​用从命令行打开的文件描述符。

标签: c linux io-redirection


【解决方案1】:

无法区分在命令行上建立的重定向和已经存在于执行环境中的重定向。

例如,当实用程序util 在脚本中运行时

exec 4<file4
# ...
util 3<file3

它将看到 fd 3 和 fd 4 都打开以供阅读;它不能说在命令行上只打开了一个。如果您关心这一点,您可能应该这样做,因为其中可能有很多。

除此之外,您当然可以确定当前打开了哪些 fd,例如通过循环浏览所有 fd 或检查 /proc/self/fd 伪目录。有关在 Linux 下查找所有打开文件描述符的示例解决方案,请参阅 this question

【讨论】:

  • 对。实际上它不会被控制台作为重定向打开,因为这些将是管道,但我认为要问这个问题,这样描述会更清楚。 /proc/self/fd 是我一直在寻找的。我想我必须小心,因为它使用 fd 来读取目录...
  • @Alexis:确实。并且不能保证没有其他打开的文件。我会补充的。
【解决方案2】:

我的命令能否确切知道在命令行中传递了多少这样的文件?

是的,如果您按顺序订购。您可以open() 一个虚拟文件(如/dev/null),然后从open 返回的fd 中减去3,以获得该过程中额外打开的文件(stdin、stdout 和stderr 除外)的数量。您可以从3 开始循环遍历它们,直到到达虚拟fd

例子:

int dummy_fd = open("/dev/null", O_RDONLY);
printf("number of files open: %d\n", dummy_fd - 3);
for(int fd_ctr = 3; fd_ctr < fd; fd_ctr++)
    /* ... */;
close(dummy_fd);

我知道我总是可以添加一个命令行选项,例如--count 14

好主意。当您使用它时,您是否也将文件名作为命令行参数传递?

【讨论】:

  • 这只适用于他按顺序编号的FD。
  • @Barmar FD 如果您在进程中打开它们,它们会按顺序编号,但这可能在这里不起作用,所以我会添加一个注释。
  • 感谢@Alexis 的编辑——这个键盘开始变得烦人了
【解决方案3】:

您的进程永远不会看到任何这些重定向。发生的情况是,shell 会将所有文件连接到等效的文件句柄(根据需要打开它们),然后运行您的代码。

您的代码所能做的就是使用已为您打开的文件句柄。如果您有间隙,您用来在代码中找到最大打开句柄的任何技巧都将不起作用,例如:

command >f1 5>f5

我怀疑您最好只使用命令行选项来执行此操作,例如:

command --output=file1 --output=file2 --output==file3

然后,您可以完全控制如何处理代码中的这些参数。例如,您可以在打开每个文件时创建文件映射。

它还允许您将不同的句柄用于其他目的,例如您需要访问的数据文件(我想如果您用与预期内容无关的输出数据覆盖它们,仅仅因为它们是已打开的文件句柄)。

【讨论】:

  • 这就是他想知道的——打开了哪些文件句柄以便他可以使用它们。
  • @Barmar,我明白了,我只是说这不是一个好主意。
  • 我的文件描述符将是管道,我的进程被另一个进程调用。所以不涉及文件名。所有管道都在内存中。
【解决方案4】:

在 linux 上,您可以只检查 /proc/self/fd/ 中的文件。每个文件名将对应一个打开的 fd。

这样的示例程序:

#include <dirent.h>
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>

int main() {
        printf("Open fds:");
        DIR *dir = opendir("/proc/self/fd/");
        assert(dir != NULL);
        struct dirent *d;
        while (d = readdir(dir), d != NULL) {
                if (d->d_type != DT_LNK) continue;
                errno = 0;
                const int i = atoi(d->d_name);
                assert(errno == 0);
                printf(" %d", i);
        }
        printf("\n");
}

执行时会这样做:

$ ./a.out 5>a 6>b 100>c
Open fds: 0 1 2 3 5 6 100

【讨论】:

  • 请注意,opendir() 也使用 fd,因此输出为 Open fds: 0 1 2 3 4 5 100
  • 哦,好点。这很容易过滤,只需if (i == dirfd(dir)) continue
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-02
  • 2015-06-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多