我有一个从调用的主方法调用的方法,该方法在某个目录上执行ls-l
,我希望它执行它,并将结果作为字符串发送到主方法。
我当前有缺陷代码:
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
在到达返回点之前被调用(。然而,我不知道我怎么可能做我想做的事,也不知道这是否真的可行。
我想使用管道和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] = ' ';
char buf[128];
size_t n;
while ((n = fread(buf, 1, sizeof(buf) - 1, fp)) > 0) {
buf[n] = ' ';
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("%sn", 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;
}
- 如果您将1024字节的缓冲区
malloc(3)
写入stringts
指针,但随后您为指针分配了一个不同的值,使您的缓冲区在RAM的巨大空间中丢失 - 当您调用
execv(2)
时,内核释放了进程的所有内存,并通过执行命令ls -l
重新加载,您将在进程的标准输出中获得输出,然后您将获得shell的提示。这会使程序的其余部分变得毫无用处,因为一旦执行,就没有回头路了,程序就会被卸载并释放 - 您可以将(
+
(添加到指针值中(您确实添加到了指向字符串"The result of the ls -l..."
的地址中,并且--由于exec的结果为零,当加载新程序时--您一无所获(。如果execv
失败,那么您将获得指向该字符串的前一个字符的指针,这在C中是一个有效的表达式,但会使您的程序以未定义的行为不稳定地运行。根据要在分配的缓冲区空间中复制的确切文本,使用strcpy(3)
、strcat(3)
或snprintf(3)
- 因此,您的
return
地址无效。这里的问题是,如果execv(2)
工作,它就不会返回。只有在失败的情况下,您才会得到一个无法使用的无效指针(由于上述原因(,当然ls -l
还没有执行。好吧,你没有说你得到了什么,所以我很难猜测你是否真的exec()
d了这个程序
另一方面,您有一个popen(3)
库函数,它允许您执行子程序,并允许您从文件描述符中读取其输出(我建议您不要在程序中免费使用chdir
,因为这是程序环境的全局变化,IMHO最好将要列为参数的目录传递给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");
}
然后你可以读取(因为它可能是很长的输出,如果你有一个巨大的目录,你可能没有足够的缓冲空间来处理内存中的所有内容(
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,因为放在这里(再次(要长得多,也要详细得多