shell C execvp用法,我遗漏了什么?

v2g6jxz6  于 2023-02-19  发布在  Shell
关注(0)|答案(2)|浏览(138)

我正在尝试为学校的一个项目编写一个使用shell命令的程序。我能够编译和运行代码而不出错,但是当我输入ls这样的命令时,什么也没有发生。我想我在execvp中遗漏了一些东西。
我一直在尝试使用各种配置的输入。

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

#define MAX_LINE 80  /* Maximum length of a command */

int main(void) {
    char args[MAX_LINE / 2 + 1]; /* command line arguments */
    int should_run = 1; /* Flag to determine when to exit the program */
    pid_t pid;
    char *myCmd;
    char *tokens[40];
    pid = fork();

    while (should_run) {
        printf("osh>");
        fflush(stdout);
        scanf("%s", myCmd);
        
        int i = 0;
        char *token = strtok(myCmd, " ");
        
        while (token != NULL) {
            tokens[i] = token;
            i++;
            token = strtok(NULL, " ");
        }
        
        if (pid < 0) {
            printf("Fork Failed\n");
            //exit(1);
        } else
        if (pid == 0) {
            execvp(tokens[0], tokens);
            //exit(1);
        } else {
            if (strcmp(tokens[i - 1], "&")) {
                waitpid(pid, NULL, 0);
            }
        }
    }
    return 0;
}
hts6caw3

hts6caw31#

除了命令输入和execvp()参数格式的严重问题之外,您在错误的位置调用fork()。您需要为shell运行的 * 每个 * 命令fork()一个新的子命令,因此fork调用应该进入循环。此外,它应该在 * 打印提示符和阅读命令之后 * 进行。因为你只想让父进程来做这些事情,而不是子进程。2你不需要父进程和子进程都来解析命令。3尽管你可以依赖子进程来做这些事情,但是在父进程中做会更传统。4但肯定不是同时在父进程和子进程中。
可以想象,尽管有其他错误,您的程序看起来仍然可以工作(尽管这不是不修复它们的理由),但是fork()的位置问题绝对是个问题,它将导致意外的额外提示,并且shell永远不会尝试执行多个命令(尽管您可能没有注意到,部分原因是您没有检查几个键函数调用的返回值)。

8i9zcol2

8i9zcol22#

    • 写入未分配内存:**
char* myCmd;

只为指针分配内存。指针具有不确定的值,即它可能指向任何对象,任何试图取消引用具有错误值的指针的操作都将导致未定义的行为。
只有在显式指定初始值时,才初始化自动和动态分配的对象;否则,它们最初具有不确定的值(通常,无论存储器中碰巧存在什么样的位模式,其甚至可能不表示该类型的有效值)。
随后对scanf()的调用会调用未定义的行为,因为没有为该字符串分配内存。

scanf("%s", myCmd);
    • 可能的修复方法:**

如果没有任何命令会超过80个字符,如以下注解所述:

define MAX_LINE 80 /*Maximum length of a command*/

您可以分配chararray[80],然后将其传递给scanf()
为了限制输入,可以指定一个宽度说明符,如下所示:

scanf("%79s", myCmd);
    • 注:**

不要使用scanf()。使用fgets()。使用scanf(),它只会获取第一个空格分隔的标记(例如,对于Hello World的输入,scanf()只会返回Hello)。-@Craig Estey

    • 指向execvp的指针数组应以空值终止:**

execv()、execvp()和execvpe()函数提供一个指针数组,指向以空值结尾的字符串,这些字符串表示新程序可用的参数列表。按照约定,第一个参数应指向与正在执行的文件关联的文件名。指针数组必须以空值指针结尾。
缺少代码:

tokens[i] = NULL;

while循环之后。
旁白:A shell in C - TutorialBeej's guide to UNIX Interprocess Communication可能有助于详细说明@John在回答中指出的内容。

相关问题