我希望当用户附加一个命令后,它将在后台执行.出于某种原因,如果我正常执行命令它将等待,然后如果我在后台执行命令它将工作,但如果我正常执行命令它将不会等待它.我确信我只是在做一些小错误的事情.有任何想法吗:
void executeSystemCommand(char *strippedCommand, char *background, int argc, char **args) {
char pathToExecute[80];
// Check if command will be executed in the background
int shellArgs;
bool bg;
if (!strcmp(background, "-")) {
bg = true;
shellArgs = argc -1;
} else {
bg = false;
shellArgs = argc;
}
// Save the linux commands in a new array
char *executableCommands[shellArgs+1];
int j;
for (j = 0; j < shellArgs+1; j++) {
executableCommands[j] = args[j];
}
executableCommands[shellArgs] = NULL;
// Check the $PATH
const char delimiters[] = ":";
char *token, *cp;
char *forLater;
int count = 0;
char *path;
path = getenv("PATH");
// All of this just breaks up the path into separate strings
cp = strdup(path);
forLater = strdup(path);
token = strtok (cp, delimiters);
while ((token = strtok (NULL, delimiters)) != NULL) {
count++;
}
char **argv;
int size = count+1;
argv = (char**) malloc (size);
count = 0;
token = strtok (forLater, delimiters);
argv[0] = (char*) malloc (50);
argv[0] = token;
strcpy(argv[0],token);
while ((token = strtok (NULL, delimiters)) != NULL) {
count++;
argv[count] = (char*) malloc (50);
argv[count] = token;
}
// This goes through the path to see if the linux command they entered
// Ex: sleep exists in one of those files and saves it to a var
int i;
bool weHaveIt = false;
int ac;
for (i = 0; i < count; i++) {
char str[80];
strcpy(str, argv[i]);
strcat(str, "/");
strcat(str, args[0]);
ac = access(str, F_OK);
if (ac == 0) {
weHaveIt = true;
strcpy(pathToExecute, str);
break;
}
}
if (!weHaveIt) {
printf("That is not a valid command. SORRY!\n");
return;
}
executableCommands[0] = pathToExecute;
int status;
// Get the array for
// If user wants command to be a background process
if (bg) {
int background_process_id;
pid_t fork_return;
fork_return = fork();
if (fork_return == 0) {
background_process_id = getpid();
addJobToTable(strippedCommand, background_process_id);
setpgid(0, 0);
execve(executableCommands[0], executableCommands, NULL);
exit(0);
} else {
return;
}
} else {
int background_process_id;
pid_t fork_return;
fork_return = fork();
if (fork_return == 0) {
background_process_id = getpid();
status = execve(executableCommands[0], executableCommands, NULL);
exit(0);
} else {
wait(&status);
return;
}
}
}
Run Code Online (Sandbox Code Playgroud)
wait对第三个作业的调用立即返回,因为第二个作业已经完成并且正在等待处理(也称为"僵尸").您可以检查返回值wait(&status),即已退出的进程的PID,并确保它是您正在等待的进程.如果不是,请wait再次打电话.
或者使用waitpid,等待特定的过程:
/* Wait for child. was: wait(&status) */
waitpid(fork_return, &status, 0);
Run Code Online (Sandbox Code Playgroud)
如果你这样做,你应该实现一个信号处理程序SIGCHLD来处理完成的后台作业,以防止"zombie"子进程的累积.
除此之外,在后台作业的情况下,fork()返回0 的分支你已经在新进程中了,所以调用addJobToTable发生在错误的进程中.此外,您应该检查所有呼叫的返回值; 否则某些事情可能会失败而你却不知道.因此,在后台运行作业的代码应该更像这样:
if (fork_return == 0) {
setpgid(0, 0);
if (execve(executableCommands[0], executableCommands, NULL) == -1) {
perror("execve");
exit(1);
}
} else if (fork_return != -1) {
addJobToTable(strippedCommand, fork_return);
return;
} else {
perror("fork"); /* fork failed */
return;
}
Run Code Online (Sandbox Code Playgroud)