将exec输出从函数发送到main方法

Sending exec output from function to main method

我有一个从 main 方法调用的方法,它在某个目录上执行 ls-l,我希望它执行它并将结果作为字符串发送到 main 方法。

我当前的有缺陷代码:

char *lsl(){
     char *stringts=malloc(1024);
      chdir("/Users/file/path");
      char * lsargs[] = { "/bin/ls" , "-l", NULL};
    stringts="The result of ls-l in the created directory is:"+ execv(lsargs[0], lsargs);
    return stringts;
}

目前我只在屏幕上得到 exec 输出,我理解 为什么会这样(exec 在到达 [=29 之前被调用=]点)。但是我不知道我怎么可能做我想做的事以及它是否真的可行。

我正在考虑使用管道和 dup2() 所以我不让 exec 函数使用 stdout 但我不知道是否可以将以字符串形式输出。

正如 Jonathan Leffler 已经在评论中指出的那样,C 中没有用于连接字符串的“+”运算符。

动态扩展字符串的一种可能性是将 realloc 与 strcat 一起使用。

对于从管道中读取的每个字节数,您可以检查最初为字符串分配的内存的剩余容量,如果这不够,则重新分配两倍大小。

您必须自己跟踪当前字符串的大小。您可以使用 size_t 类型的变量来执行此操作。

如果将它与 popen 处理结合起来,它可能看起来像这样:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void) {
    FILE *fp;
    if ((fp = popen("ls -l", "r")) == NULL) {
        perror("popen failed");
        return EXIT_FAILURE;
    }

    size_t str_size = 1024;
    char *stringts = malloc(str_size);
    if (!stringts) {
        perror("stringts allocation failed");
        return EXIT_FAILURE;
    }
    stringts[0] = '[=10=]';

    char buf[128];
    size_t n;
    while ((n = fread(buf, 1, sizeof(buf) - 1, fp)) > 0) {
        buf[n] = '[=10=]';
        size_t capacity = str_size - strlen(stringts) - 1;
        while (n > capacity) {
            str_size *= 2;
            stringts = realloc(stringts, str_size);
            if (!stringts) {
                perror("stringts realloation failed");
                return EXIT_FAILURE;
            }
            capacity = str_size - strlen(stringts) - 1;
        }
        strcat(stringts, buf);
    }
    printf("%s\n", stringts);
    free(stringts);
    if (pclose(fp) != 0) {
        perror("pclose failed");
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}

你的代码有几个缺陷:

char *lsl(){
     char *stringts=malloc(1024);
      chdir("/Users/file/path");
      char * lsargs[] = { "/bin/ls" , "-l", NULL};
    stringts="The result of ls-l in the created directory is:"+ execv(lsargs[0], lsargs);
    return stringts;
}
  • 如果您 malloc(3) 将一个 1024 字节的缓冲区放入 stringts 指针,但随后您为该指针分配了一个不同的值,从而使您的缓冲区在您的巨大 RAM 中丢失。
  • 当您执行 execv(2) 调用时,您的进程的所有内存都被内核释放并通过执行命令 ls -l 重新加载,您将在标准输出中获得输出的过程,然后你会得到shell的提示。这会使您的程序的其余部分无用,因为一旦执行,就无法返回,您的程序将被卸载并释放。
  • 您可以将 (+) 添加到一个指针值(您确实添加到指向字符串 "The result of the ls -l..." 的地址并且 --- 因为 exec 的结果是什么,作为一个新的程序已加载---你什么也得不到)如果 execv 失败,那么你会得到一个指向该字符串的前一个字符的指针,这是 C 中的有效表达式,但会使你的程序在 Undefined 中表现不稳定行为。使用 strcpy(3)strcat(3)snprintf(3),具体取决于您要复制到您分配的缓冲区的 space 中的确切文本。
  • 您的 return 结果是一个无效地址。这里的问题是,如果 execv(2) 有效,它不会 return。只有当它失败时,你才会得到一个你不能使用的无效指针(由于上述原因),当然 ls -l 还没有被执行。好吧,你没有说你得到了什么作为输出,所以我很难猜到你是否真的 exec()d 程序。

另一方面,您有一个 popen(3) 库函数,它允许您执行子程序并允许您从文件描述符中读取其输出(我建议您不要无故地 chdir您的程序,因为这是您程序环境中的全局更改,恕我直言,最好将 ls(1) 您要列出的目录作为参数传递)

#include <stdio.h>

FILE *lsl() {
    /* the call creates a FILE * descriptor that you can use as input and
     * read the output of the ls command. It's bad resources use to try to
     * read all in a string and return the string instead. Better read as
     * much as you can/need and then pclose() the descriptor. */
    return popen("/bin/ls -l /Users/file/path|", "rt");
}

然后你可以阅读(因为它可能是很长的输出,如果你有一个巨大的目录,你可能没有足够的缓冲区 space 在内存中处理它)

FILE *dir = lsl();
if (dir) {
    char buffer[1024]; 
    while (fgets(buffer, sizeof buffer, dir)) {
        process_line_of_lsl(buffer);
    }
    pclose(dir); /* you have to use pclose(3) with popen(3) */
}

如果你不想使用popen(3),那么你不能单独使用execv(2),你必须先fork(2),创建一个新进程,然后exec() 在子进程中(在你自己安装重定向之后)。阅读 fork()/exec() 以及如何在 fork()exec() 之间重定向 I/O 的很好的介绍,因为将它放在这里更长更详细(再次)