Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/69.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在unix C shell中使用fork()时出现意外行为_C_Shell_Unix_Fork_Execvp - Fatal编程技术网

在unix C shell中使用fork()时出现意外行为

在unix C shell中使用fork()时出现意外行为,c,shell,unix,fork,execvp,C,Shell,Unix,Fork,Execvp,当我在setup()函数之外分叉并调用execvp()时,一切似乎都正常工作。但是,我想检测输入是否为有效命令,如果命令有效,则返回一个整数。这样,如果该命令有效,我可以将其添加到历史记录中。然后,我可以使用“rn”从历史运行命令,其中N是任意数,然后再次将该命令(而不是“rn”)重新存储在我的历史中。在我将fork()移到setup()函数中之前,一切都按照我想要的方式工作。现在,我正在setup()中分叉并运行命令,但发生了两件我不理解的事情 1) 如果我键入一个命令和一些标志,则只有该命令

当我在setup()函数之外分叉并调用execvp()时,一切似乎都正常工作。但是,我想检测输入是否为有效命令,如果命令有效,则返回一个整数。这样,如果该命令有效,我可以将其添加到历史记录中。然后,我可以使用“rn”从历史运行命令,其中N是任意数,然后再次将该命令(而不是“rn”)重新存储在我的历史中。在我将fork()移到setup()函数中之前,一切都按照我想要的方式工作。现在,我正在setup()中分叉并运行命令,但发生了两件我不理解的事情

1) 如果我键入一个命令和一些标志,则只有该命令存储在历史记录中,并且标志被截断。我看不到正在删除标志的位置。
2) 如果我键入“rn”以运行历史记录中的第N个命令,“rn”将存储回历史记录,而不是第N个命令

例如:
在我将fork()和execvp()移动到setup()之前,我可以键入
ls-al&
,整个字符串将存储到
*history[]
中。现在只存储了
ls
。 然后,如果我想重新运行该命令,我可以键入
r1
,并且
ls-al&
将再次添加到
*history[]
数组中。现在
r1
被添加到历史记录中

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h> // to use system calls
#include <string.h> // to use string functions
#include <signal.h> // to handle Ctrl-C

#define MAX_LINE 80
#define BUFFER_SIZE 50
char *history[MAX_LINE];    // a list to hold each command entered
int cmdNum = 0;             // keep track of the number of commands entered

void handle_SIGINT() {      // if control C is detected then list the last 10 input commands
    int displayNum = cmdNum;
    printf("\n");
    int i = 10;
    int j = cmdNum -1;
    while(i > 0 && j > -1) {
        printf("%d %s\n", displayNum, history[j]);
        i--;
        j--;
        displayNum--;
    }
}

/* setup() reads in the next command line, separateing it into distinct
 * tokens using whitespace as delimiters. setup() modifies the args
 * parameter so that it holds pointers to the null-terminated strings
 * that are the tokens in the most recent user command line as well
 * as NULL pointer, indicating the end of the argument list. setup()
 * calls exit() when Controld-D is entered. */

int setup(char inputBuffer[], char *args[], int *background) {

    char *hasInput = fgets(inputBuffer, MAX_LINE, stdin);   // grab user input
    char *arguments;                                        // temporary string to hold input as it's split into separate strings
    int i = 0;                                              // place holder for moving forward in args[]


    char last = inputBuffer[(strlen(inputBuffer)-1)];       // check the last character in inputBuffer
    if(last == '&') {                                       // is the last character '&'
        *background = 1;
    }

    if(hasInput == NULL) {                                  // check for control D and exit
        printf("\n");
        exit(EXIT_SUCCESS);
    } else if(strlen(inputBuffer) < 2) {                    // is inputBuffer empty?
        return 0;
    } else {
        inputBuffer = strtok(inputBuffer, "\n");            // remove \n from the end of the inputBuffer
        char *forHistory = strdup(inputBuffer);             // make a copy of the input because its original value gets modified
        char *tempInput = strdup(inputBuffer);              // copy input again because it gets modified after strtok
        arguments = strtok(tempInput, " \n");               // get the first string from inputBuffer before a " " appears
        if (*arguments == 'r') {                            // is the first string just the character 'r'?
            arguments = strtok(NULL, " \n");                // resume splitting input buffer from where it left off
            char *safetyString;
            if((strtol(arguments, &safetyString, 10) -1) > -1 &&        // take the next argument after the letter r and turn it into an integer
                    (strtol(arguments, &safetyString, 10) -1) <= cmdNum -1 &&
                    history[0] != 0) {
                int cmdToRun = strtol(arguments, &safetyString,10) - 1; // subtrack 1 from the integer since arrays start at 0
                inputBuffer = strdup(history[cmdToRun]);                // inputBuffer should be equal to a runnable command from history and not "r #"
                forHistory = strdup(history[cmdToRun]);                 // change forHistory as well, because we don't want to save "r #" in history
                printf("forHistory: %s\n", forHistory);
            } else {
                printf("Command not in history.\n");
                return 0;
            }
        }

        if(*background == 1) {                              // remove the '&' from inputBuffer before storing each string in args
            inputBuffer[(strlen(inputBuffer)-1)] = 0;
        }

        arguments = strtok(inputBuffer, " \n");             // get the first string from inputBuffer before a " "
        while(arguments != NULL) {
            args[i] = arguments;                            // place each space separated string into args
            arguments = strtok(NULL, " \n");                // resume splitting inputBuffer from where it left off
            i++;
        }
        args[i] = 0;                                        // add the null terminator to args

        pid_t pid;
        int status;

        if((pid = fork()) < 0) {            // make sure fork() works
        } else if(pid == 0) {               // if this is a child process
            if(execvp(args[0], args) < 0) { // try to execute command
                // if the program gets here then execvp() failed
                printf("execvp failed, ivalid command\n");
                return 0;
                //exit(EXIT_FAILURE);
            }
        } else if(*background == 0) {       // unless specified wait for the the child to finish
            while(wait(&status) != pid);
            inputBuffer = strdup(forHistory);
            //printf("inputBuffer after = forHistory: %s\n", inputBuffer);
            return 1;
        }
    }
}

int main(void) {
    char inputBuffer[MAX_LINE];     // buffer to hold command entered
    int background;                 // equals 1 if a command is folled by '&'
    char *args[MAX_LINE/2+1];       // command line arguments

    while(1) {
        background = 0;
        printf("COMMAND->");

        struct sigaction handler;
        handler.sa_handler = handle_SIGINT;
        sigaction(SIGINT, &handler, NULL);
        siginterrupt(SIGINT, 0);


        if(setup(inputBuffer, args, &background)) {
            //printf("inputBuffer before history placement: %s\n", inputBuffer);
            history[cmdNum] = strdup(inputBuffer);              // copy the comand to history
            cmdNum++;
        }
        /* the steps are:
         * (1) fork a child process using fork()
         * (2) the child process will invoke execvp()
         * (3) if background == 0, the parent will wait,
         * otherwise it will invoke the setup() function again */
    }
}
#包括
#包括
#包含//以使用系统调用
#include//以使用字符串函数
#包含//以处理Ctrl-C
#定义最大行80
#定义缓冲区大小为50
字符*历史[最大行];//保存输入的每个命令的列表
int cmdNum=0;//跟踪输入的命令数
void handle_SIGINT(){//如果检测到控件C,则列出最后10个输入命令
int displayNum=cmdNum;
printf(“\n”);
int i=10;
int j=cmdNum-1;
而(i>0&&j>-1){
printf(“%d%s\n”,displayNum,history[j]);
我--;
j--;
displayNum--;
}
}
/*setup()读入下一个命令行,将其分隔为不同的
*使用空格作为分隔符的标记。setup()修改参数
*参数,以便它保存指向以null结尾的字符串的指针
*这也是最新用户命令行中的令牌
*作为空指针,指示参数列表的结尾。设置()
*输入Controld-D时调用exit()*/
int设置(char inputBuffer[],char*args[],int*background){
char*hasInput=fgets(inputBuffer,MAX_LINE,stdin);//获取用户输入
char*arguments;//将输入拆分为单独的字符串时用来保存输入的临时字符串
int i=0;//在args[]中向前移动的占位符
char last=inputBuffer[(strlen(inputBuffer)-1)];//检查inputBuffer中的最后一个字符
如果(last=='&'){//是最后一个字符'&'
*背景=1;
}
如果(hasInput==NULL){//检查控件D并退出
printf(“\n”);
退出(退出成功);
}否则如果(strlen(inputBuffer)<2){//inputBuffer是空的吗?
返回0;
}否则{
inputBuffer=strtok(inputBuffer,“\n”);//从inputBuffer的末尾删除\n
char*forHistory=strdup(inputBuffer);//复制输入,因为其原始值被修改
char*tempInput=strdup(inputBuffer);//再次复制输入,因为它在strtok之后被修改
arguments=strtok(tempInput,“\n”);//在出现“”之前从inputBuffer获取第一个字符串
如果(*arguments=='r'){//第一个字符串就是字符'r'吗?
arguments=strtok(NULL,“\n”);//从停止位置继续拆分输入缓冲区
字符*安全字符串;
if((strtol(arguments,&safetyString,10)-1)>-1&&//取字母r后的下一个参数,并将其转换为整数

(strtol(arguments,&safetyString,10)-1)
void handle\u SIGINT(void){}
应该是
void handle\u SIGINT(int signum){…}
并且您不应该从信号处理程序中调用printf()。(1)您的意外行为与
fork
无关。请使用调试器解决此问题。(2)你不能报告一个成功的
exec
,所以你不能只在你的历史记录中存储成功的命令。存储所有命令。@n.m.Ok,所以当我尝试
ls-al
时,用printf()选中main()中的
inputBuffer[4]
,它会按预期打印
a
。所以它不是fork(),但我假设我的赋值
history[cmdNum]=strdup(inputBuffer)有问题
。我正在尝试将一个字符数组分配给指针。有没有办法将字符数组转换为指针?你的程序是一个可怕的指针/数组混乱和内存错误处理的烂摊子。从开始到中间到结束,基本上都是完全错误的。我不知道如何修复它,只能将它全部扔掉并重新启动rting over.Sorry.the函数:strdup()正在广泛使用,但是;strdup()分配内存。因此,在离开程序之前,内存需要空闲()。