gpt4 book ai didi

c - 为什么这段代码没有被执行?

转载 作者:太空宇宙 更新时间:2023-11-04 08:17:03 25 4
gpt4 key购买 nike

我目前正在制作自己的 shell 程序。我必须保留用户输入的最后 10 个命令的历史记录。每当用户输入不是常规命令的命令(例如 history、hi、fakecommand 等)时,它就会被放入历史记录中。但是每当用户输入一个真正的命令(例如 ls、ps、top、cat 等)时,它都不会添加到历史记录中。

我认为它可能与 execvp 命令有关,因为我相信该命令会创建一个分支并让子进程执行该命令。但我不确定它是否应该这样做,因为我什至在执行 execvp 之前就将命令放在了历史记录中。

//A method which increments the histIndex
int incrementIndex(int index) {
if (index != 9)
return index+1;
else
return 0;
}

//A method which adds the current command to history
void updateHistory(char *history[], char command[], int histIndex) {

history[histIndex] = realloc(history[histIndex], MAX_LENGTH); //Allocating space
strcpy(history[histIndex], command); //Put the current command in history
}

int main(int argc, char *argv[]) {
//while true, do
while (1) {

int pid = fork(); //fork, or start the first process
if (pid != 0) { //if pid is not 0, then this is the parent,
wait(NULL);
}

else { //Otherwise, we have the child

printf("%s> ", getenv("USER")); //print out the user's name + >
fgets(input, MAX, stdin); //Get the users input
strtok(input, "\n"); //Take the entire line and set it to input

updateHistory(history, input, histIndex); //Updating history
histIndex = incrementIndex(histIndex);

if (strcmp(input, "exit")==0) { //If the input is exit, then exit
exit(0);
}

//Else if the current command is history, then print the last 10 commands
else if (strcmp(input, "history")==0) {
getHistory(history, histIndex);
}

//Otherwise, do
else {
numTokens = make_tokenlist(input, tokens);

tokens[numTokens] = NULL;
char cmd[MAX_LENGTH];
strcpy(cmd, tokens[0]);
execvp(cmd, tokens);
printf("Error: %s not found.\n", cmd);
}
}
}
}

最佳答案

单独的进程有自己独立的内存空间(除非你做了一些特殊的事情,比如共享内存等)。无论您在子进程中对堆或堆栈结构进行什么更新(例如修改历史记录),都不会影响父进程。

您正在使用 fork() 创建一个子对象,然后读取用户输入在子对象中。 child 更新自己的历史副本,这对 parent 知道的任何历史都没有影响。 execvp() 不 fork ,它用执行的文件替换当前进程。这会替换整个子进程,并且您会丢失仅在子进程中更新的历史记录。

你也有 child 生 child ,这可能不是你想要的,但解释了为什么你认为它在历史中添加了无效的命令。 (是的,但不正确。)事件顺序的说明:

    Parent    ------    fork()  ------>   Child    wait()            -----     ...              Read input     ...              updateHistory()     ...              exit if "exit"     ...              print history if "history"     ...              execvp()                      (if execvp() succeeded, this child is consumed,                      the executed file eventually terminates and the                      parent stops waiting. If execvp() failed, we fall                       through back to the top of the while loop!)                      fork()   --------->    Child's Child                      wait()                 -------------                      ...                    Read input                      ...                    updateHistory()                      ...                    exit if "exit"                      ...                    print history if "history"                      ...                    execvp()

child 的 child 继承了 child 的内存,所以知道更新的历史。这就是为什么您认为它将失败的命令添加到历史记录中的原因。确实如此,但实际上比这更糟糕。

看起来你应该在parent中读取输入,在parent中更新历史,然后(给定一个有效的命令),fork 关闭由 execvp 消耗的子进程来运行命令。然后让父级等待 子级完成。这样, parent 维护历史。 fork 子进程的一个主要目的是因为 execvp 替换了调用进程。既然你想让 parent 活下去,你就让它吃掉 child 。

尝试这样的事情(我将其保留为抽象伪代码):

    Parent    ------    Read input    updateHistory()    exit if "exit"    print history if "history"    if invalid, go back to [Read input]    if valid:        fork()  ------>   Child        wait()            -----        ...               execvp()        ...     <-------  if successful, executable hopefully terminates        ...     <-------  if failed, print error and exit                          (either way, child ends)    Parent goes back to [Read input]

另一件值得一提的事情是,每当您fork() 时,您应该检查三个可能的返回值:-1(fork() 中的错误)、>0(在父进程中)和 0(在子进程中)。

关于c - 为什么这段代码没有被执行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35237531/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com