2016-02-06 3 views
0

В настоящее время я делаю свою собственную программу оболочки. Мне нужно сохранить историю последних 10 команд, которые пользователь вводит. Всякий раз, когда пользователь вводит команду, которая НЕ является обычной командой (например, история, привет, 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); 
     } 
    } 
} 
} 
+0

Функция '' '' '' '' '' '' '' '' 'приведет к утечке памяти, поскольку она не передает никакого существующего указателя выделения памяти в' history [] '' 'free()' перед тем, как сделать новое распределение. – user3629249

+0

отправьте функцию 'incrementHistory()' – user3629249

+0

после этой строки: 'printf (« Ошибка:% s не найден. \ N », cmd)' вставьте строку: 'exit (EXIT_FAILURE);', поскольку вы не хотите, чтобы ребенок должен действовать как родитель. – user3629249

ответ

2

Отдельные процессы имеют собственное пространство памяти (если только вы не делаете что-то особенное, как разделяемая память и т. Д.). Независимо от того, какие обновления для структур кучи или стека вы выполняете в дочернем процессе (например, для изменения истории), не имеет никакого эффекта в родительском.

Вы создаете ребенка с fork(), затем читаете ввод пользователя у ребенка. Ребенок обновляет свою собственную копию истории, которая не влияет на историю, о которой знает родитель. execvp() не fork, он заменяет текущий процесс исполняемым файлом. Это заменяет весь дочерний процесс, и вы теряете историю, которую вы только обновили в дочернем.

У вас также есть дети, делающие детей, что, вероятно, не то, что вы хотите, но объясняет, почему вы думаете, что он добавляет неверные команды в историю. (Это, но не правильно.) Иллюстрация последовательности событий: ребенок

 
    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() 

ребенка унаследовал память ребенка, поэтому он знает об обновленной истории. Вот почему вы думаете, что добавляет неудавшиеся команды в историю. Это так, но на самом деле это намного хуже.

кажется, что вы должны читать вход в родителя, обновляя историю в родителя, затем (с учетом действительной команды), fork от дочернего процесса потребляться execvp для выполнения команды. Затем пусть родительский wait для ребенка закончен. Таким образом, родитель поддерживает историю. Одна из основных целей для разветвления ребенка в первую очередь состоит в том, что execvp заменяет вызывающий процесс. Поскольку вы хотите, чтобы родитель жил, вы позволяете ему есть ребенка.

Попробуйте что-то вроде этого (я оставлю это как абстрактный псевдокод):

 
    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 (в дочернем процессе).

+0

Ok. Поэтому причина, по которой действительная команда не добавляется, заключается в том, что execvp заменяет мой текущий процесс памятью дочернего процесса до обновления истории? – Logan

+0

'execvp' заменяет ** весь дочерний процесс **. Вы обновляете память только тогда, когда вы «updateHistory()». Затем вы вызываете 'execvp', и ребенок потребляется. История родителя не затронута, потому что вы его никогда не изменяли. – e0k

+0

Это было отличное объяснение. На самом деле я не могу поблагодарить вас за то, что объяснил это мне! – Logan

Смежные вопросы