【发布时间】:2017-05-16 21:47:12
【问题描述】:
我正在做一个模拟 shell 程序来练习 C 和 Linux 命令功能,execvp()。我知道,每当返回值小于 0 时,执行在execvp 中传递的命令时就会出错。我对我的stringTok() 函数处理句子数组字符正确传入是肯定的,因为我打印了它们的长度和字符串值进行双重检查。对于句子的最后一个标记,本质上是将参数列表分成单独的标记,我将'\0' 字符分配给该标记的最后一个字符。
最终,每个单独的令牌都被分配给char*cmdargv[MAX_LINE]in stringTok()。 execvp(cmdargv[0], cmdargv) 是我传递命令参数的方式。例如,“ls -al”是输入,fgets() 函数将该字符串读入args[MAX_LINE]。子进程将运行execvp,但返回负值并打印出错误字符串。这甚至不起作用,因为我尝试按照代码中的注释手动为 cmd 和 argv 分配值。我想我一定是在 execvp() 中传递了错误的值,或者做错了什么。
理想情况下,如果我输入“ls -al”,它应该与在 linux shell 中的操作完全相同,列出当前目录中的所有文件或目录(预期输出)。
输入:
osh>ls -al
输出:
参数:
镜头 2
内容:ls
最后一个元素 115
镜头 3
内容:-al
最后一个元素 108
最后一个成员:(null)
osh>错误:: 错误地址
最后一个成员:(null)
osh>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#define MAX_LINE 80
int stringTok(char* sentence, char** tokens) {
const char* delim = " \r\n";
int count = 0;
// make copy of sentence for strtok
size_t len = strlen(sentence);
char *copy = malloc(len+1);
if(!copy) return 0; // if copy null, return 0
strncpy(copy, sentence, len);
copy[len] = '\0';
// Allocate and copy tokens
for(char* word = strtok(copy, delim);
word;
word = strtok(NULL, delim))
{
size_t len = strlen(word);
tokens[count] = malloc(len+1);
if(!tokens[count]) break;
strncpy(tokens[count], word, len);
tokens[count][len] = '\0';
count++;
}
size_t strlenth = strlen(tokens[count - 1]);
//if(count > 1) {
// tokens[count - 1][strlenth -1] = '\0';
//}
tokens[count] = NULL;
return count;
}
int main(void) {
char args[MAX_LINE]; // command to be executed
char *cmdargv[MAX_LINE]; // command tokens
int should_run = 1;
do {
printf("osh>");
fflush(stdout);
fgets(args, MAX_LINE, stdin);
//fflush(stdout);
printf("args:<%s>\n", args);
int count = stringTok(args, cmdargv);
for(int i = 0; i < count; i++) {
printf("len %ld\n", strlen(cmdargv[i]));
printf("content: %s\n", cmdargv[i]);
printf("last elememnt %d\n", cmdargv[i][strlen(cmdargv[i]) - 1]);
}
cmdargv[count] = NULL;
printf("last member:%s", cmdargv[count]);
//printf("cmdargv:%s\n", cmdargv[0]);
//printf("cmdargc:%d\n", cmdargv[0][strlen(cmdargv[0]) - 1]);
int pid = fork();
char *cmd = "ls";
char *argv[3];
argv[0] = "ls";
argv[1] = "-la";
if(pid == 0) {
execvp(cmd, argv);
if(execvp(cmd, argv) < 0) {
//printf("Error Executing Command\n");
perror("Error:");
}
} else if (pid > 0) {
// if '&' {
// wait(&pid)
//}
} else {
printf("Fork failed\n");
exit(1);
}
printf("\n");
} while(should_run);
return 0;
}
【问题讨论】:
-
@NateLee:您认为
execvp()怎么知道您传递给它的参数数量?如果您阅读手册页,您会看到传递给execvp()的参数列表必须由NULL指针终止。 -
@NateLee,不要忽略我之前评论的 first 部分,关于将您的代码简化为 MCVE。或者您甚至可以从另一个方向着手,从头开始构建 MCVE。一般来说,尽一切合理努力提出我们容易回答的问题。这样你会得到更好的答案。
-
您不需要
if— 只需使用execvp(cmdargv[0], cmdargv);,因为如果execvp()成功,则此进程(可能是子进程)在execvp()之后不会返回。如果execvp()完全返回,它就失败了。当您成功使用execvp()时,您指定的命令将完全替换当前进程。父进程将发现失败,因为退出状态将非零。请注意,您应该将错误消息打印到标准 error,而不是标准输出。我还观察到,您通常应该在失败时退出 - 使用exit()或_exit()或类似名称。 -
fgets(args, MAX_LINE, stdin); fflush(stdout);很奇怪。我希望fflush(stdout); fgets(args, MAX_LINE, stdin); -
@NateLee:您仍然没有尝试找出 为什么
execvp()失败。据我们所知,它可能无法找到文件,或者权限问题,或者您可能已经达到了您的进程限制,而与您的代码无关。失败后拨打perror()查询原因。
标签: c system-calls