问题描述
我正在尝试使用C99 / gcc / Linux(unistd.h)编写一个程序,以从用户处接收Linux Shell命令,执行它们,检索其输出并将其存储在动态大小的数组/字符串中以进行输出/稍后进行修改。
在下面的代码中,我一次将Shell命令一次传递给该函数(char * cmd
),希望使用一个链接的字符列表({{1 }})甚至是动态分配的足以容纳所有数据的字符串,因为某些命令可能返回5个字符(node * charLinkedList
),而其他命令可能返回很多(pwd
)。
我已经彻底测试并确认以下各项可以正常工作:
- 存储/检索/打印到字符链接列表
- 派生该进程并使子进程执行命令(不使用管道)
- 执行shell命令并将其打印到控制台(不使用管道)
- 执行带有和不带有不同长度参数的shell命令
什么不起作用:
- 将每个命令的输出插入变量/链表
cat [file]
我尝试使用#define READPIPE 0
#define WRITEPIPE 1
/* % Inputs %
* char * cmd : a string containing the command
* node * charLinkedList : a linked list of char to store the output */
void execCmd(char * cmd,node * charLinkedList) {
int fd[2]; // fd is the pipe
pid_t pid; // pid is for holding the process ID
char* shellOutput; // shellOutput is a string to store the output in,it's
//> not being used in this code but I'm ok using it in place
//> of my character linked list (charLinkedList)
if(pipe(fd) == -1){
fprintf(stderr,"Pipe Failed");
}
/* Logic for separating the command from it's arguments */
int argNum = argumentCounter(cmd); // argNum counts the arguments and returns it
char * args[argNum + 2]; // for holding the arguments that we will be passing later on
char ** delimArguments; // to hold the deliminated command string
if(argNum > 0) { //if there are arguments with the command
delimArguments = stringSplitter(cmd,' '); //stringSplitter splits the string at a deliminer and returns it
for (int i = 0; i < (argNum + 1); i++){ //loads the commands into an array
args[i] = *(delimArguments + i); // this logic has been tested and works
}
args[argNum + 1] = 0; // please ignore this spaghetti code,I'll clean
} //> it up later I promise
/* Forking & executing the commands */
pid = fork();
if(pid == -1) {
printf("FORK Failed\n");
}
if (pid == 0) { /* Child Process */
close(fd[READPIPE]); // same as close(fd[0])
/* This next if/else statement is for toggling between whether or not the
* command has arguments or not. It's a mess and I'll 100% be merging
* this at a later date. */
if (argNum > 0){
/* command with arguments */ //i.e. ls -l -a
dup2(fd[WRITEPIPE],STDOUT_FILENO); //duplicate the STDOUT to the write end of the pipe (fd[1])
execvp(args[0],args); //execute the command and it's arguments
} else {
/* command without argument */ //i.e. ls
dup2(fd[WRITEPIPE],STDOUT_FILENO); //duplicate the STDOUT to the write end of the pipe (fd[1])
execlp(cmd,cmd,NULL); //execute the command
}
close(fd[WRITEPIPE]); //if something goes wrong and the code gets to here,close the pipe
return; //return to int main() function; don't continue this one as the child
} else { /* Parent Process */
close(fd[WRITEPIPE]); //closing the writing side of the pipe
fcntl(fd[READPIPE],F_SETFL,fcntl(fd[READPIPE],F_GETFL) | O_NONBLOCK); //using fcntl to get the file descriptor of the pipe
FILE * theOutput; // creating a file to point at the output
theOutput = fdopen(fd[READPIPE],"r"); // opening the stream from the child process
char buffer; // a char for grabbing output one character at a time
while((buffer = fgetc(theOutput)) != NULL) // while we havn't hit the end of the file
{
addToQueue(charLinkedList,buffer); // one by one add each character of the output to
} //> the linked list queue
printLinkedList(charLinkedList); //outputting the list to verify the output captured
}
和read()
函数,尽管无法正常工作。我实现了dup2以将write()
克隆到管道中,然后从那里开始与之战斗,试图使其正常工作(没有成功)。我发现another post建议按照目前的方式来做事,尽管我不知道如何从文件描述符中获取输出。
我尝试同时使用STDOUT
和fgetc
都无济于事,这有点困扰。这是正确的方法,还是有更好的方法将子进程的fgets
输出输出到父进程的字符串/链接列表/ 变量中?
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)