当我在loading()函数之外分叉并调用execvp()时,一切似乎都正常工作。但是我想检测输入是否是有效命令,如果命令有效则返回整数。这样我就可以将命令添加到我的历史记录中,如果它是一个有效的命令。然后,我可以使用" r N"运行历史记录中的命令,其中N是任意数字,然后再次在我的历史记录中重新存储该命令(不是" r N")。在我将fork()移动到setup()函数之前,一切都按照我想要的方式工作。既然我在setup()中分叉和运行命令,那么我发现了两件我不理解的事情。
1)如果我输入一个命令和一些标志,只有命令存储在历史记录中并且标志被切断。我不知道旗帜被移除的位置 2)如果我键入" r N"在历史中运行第N个命令," r N"存储回历史而不是第N个命令。
所以例如:
在将fork()和execvp()移动到setup()之前,我可以输入ls -al &
,整个字符串将存储到*history[]
中。现在只存储了ls
。
然后,如果我想重新运行该命令,我可以键入
r 1
,ls -al &
将再次添加到*history[]
数组中。现在r 1
已被添加到历史记录中。
#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 */
}
}