所以,我认为我尝试模仿bash shell是正确的,但我遇到了管道问题。执行第二个命令时出错。我想知道是否有人可以向我解释如何修复这个问题以及为什么会出错。
我对C&Linux命令,所以任何补充信息,可以帮助我的道路上,也将不胜感激。
非常感谢您抽出时间。下面是我的代码,但有很多代码。我的问题出现在exec_pipe函数中。我通常会包括我用于输入的内容和我用于输出的内容,但我的示例输入实际上是我教授给我们测试的可执行文件。不幸的是,我的不像在壳里那样工作。我正在打印错误:
Inside Case 5
Inside Exec_Pipe
Error in Pipe EXECVP cmd2
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdbool.h>
#include <time.h>
#include <limits.h>
#include <fcntl.h>
#include <sys/wait.h>
#define BUFSIZE 1024
#define CSTRSIZE 100
#define CMDSIZE 30
#define DEBUG 1
//I referenced our blackboard source code files to create the fork functions and to deal with file descriptors
void exec_cmd(char** cmd1){
pid_t pid;
if((pid = fork()) < 0){
printf("Child Process Failed\n");
}else if(pid == 0){
if(execvp(cmd1[0], cmd1) < 0){
printf("Execution Failed\n");
exit(1);
}
}else{
wait(NULL);
}
}
void exec_cmd_in(char** cmd1, char* infile){
pid_t pid;
int fdi;
if((pid = fork()) < 0){
printf("Child Process Failed\n");
}else if(pid == 0){
fdi = open(infile, O_RDONLY);
if(fdi == -1){
printf("No Infile");
}
}
}
void exec_cmd_opt_in_append(char** cmd1, char* infile, char* outfile){
/* pid_t pid;
int fdi, fdo;
if((pid = fork()) < 0){
printf("Child Process Failed\n");
}else if(pid == 0){
fdo = open(outfile, O_RDWR | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR);
if(fdo == -1){
printf("No Outfile");
}
if(dup2(fdi, 0) == -1){
printf("Infile not updated");
}
if(dup2(fdo, 1) == -1){
printf("Outfile not updated");
}
close(fdi);
close(fdo);
if(execvp(cmd1[0], cmd1) < 0){
printf("Execution Failed\n");
exit(1);
}
}else{
wait(NULL);
} */
}
void exec_cmd_opt_in_write(char** cmd1, char* infile, char* outfile){
/* pid_t pid;
int fdi, fdo;
if((pid = fork()) < 0 ){
printf("Fork Error");
exit(1);
}else if(pid == 0 ){
fdo = open(outfile, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
if(fdo == -1){
printf("No Outfile");
}
if(dup2(fdi, 0) == -1){
printf("Infile not updated");
}
if(dup2(fdo, 1) == -1){
printf("Outfile not updated");
}
close(fdi);
close(fdo);
if(execvp(cmd1[0], cmd1) < 0){
printf("Execution Failed\n");
exit(1);
}
}else{
wait(NULL);
}
*/
}
void exec_pipe(char** cmd1, char** cmd2){
pid_t pid;
int pipefd[2];
// pipe[1] is the write end of the pipe
// pipe[0] is the read end of the pipe
// making a pipe
printf("Inside Exec_Pipe\n");
pid = fork();
switch(pid){
case -1:
//error in fork
printf("Fork Error\n");
//Exit
exit(1);
case 0:
//child
break;
default:
//parent
wait(NULL);
}
//This will be executed by child process
if(pipe(pipefd) < 0 ) {
//error condition
printf("Pipe Error");
exit(1);
}
pid = fork();
switch(pid){
case -1:
//error in fork
printf("Fork Error\n");
//Exit
case 0:
//child
close(STDIN_FILENO);
//direct STDOUT to the pipe
dup2(pipefd[1], STDOUT_FILENO);
//Close descriptors
close(pipefd[0]);
close(pipefd[1]);
//Execute Command1
execvp(cmd1[0], cmd1);
//execvp should not return, so if it does
//there is an error!
printf("Error in EXECVP cmd1");
exit(1);
default:
//parent
close(STDIN_FILENO);
//direct input to the pipe
dup2(pipefd[0],STDIN_FILENO);
//close descriptors
close(pipefd[0]);
close(pipefd[1]);
//execute command 2
execvp(cmd2[0],cmd2);
//if execvp makes it back, error condition
printf("Error in Pipe EXECVP cmd2");
exit(1);
}
}
void exec_pipe_opt_in_append(char** cmd1, char** cmd2, char* infile, char* outfile){
}
void exec_pipe_opt_in_write(char** cmd1, char** cmd2, char* infile, char* outfile){
}
int parse_command(char* line, char** cmd1, char** cmd2, char* infile, char* outfile){
/*
(1)Create a bunch of flags to compare for the right return value
(2)Loop over the entire line and set the flags
(3)Add a bunch of if statements to compare flags
(4)If there is more than one flag for pipe, we can't handle it. Regurn 9.
(5)If there is &, we can't handle.
(6)Return the right value
*/
int pipe_found = 0;
int input_found = 0;
int redirection = 0;
int i = 0;
int spaces = 0;
int append = 0;
int special = 0;
while(line[i] != '\0'){
if(line[i] == '|'){
pipe_found++;
}
if(line[i] == '<'){
input_found = 1;
}
if((line[i] == '&') || (line[i] == '*') || (line[i] == '^') || (line[i] == '%') || (line[i] == '#') || (line[i] == '!') || (line[i] == '@') || (line[i] == '(') || (line[i] == ')')){
special = 1;
}
if(line[i] == '>'){
redirection = 1;
if(line[i+1] == '>'){
append = 1;
}
}
if(line[i] == ' '){
spaces++;
}
i++;
}
if((strlen(line) >=4) && (line[0] == 'q') && (line[1] == 'u') && (line[2] == 'i') && (line[3] == 't')){
return 0;
}
if((pipe_found == 0) && (special == 0)){
if((redirection == 0) && (input_found == 0)){
return 1;
}else if((redirection == 0) && (input_found == 1)){
return 2;
}else if(append == 1){
return 3;
}else if(redirection == 1){
return 4;
}
}else if((pipe_found == 1) && (special == 0)){
if((redirection == 0) && (input_found == 0)){
return 5;
}else if((redirection == 0) && (input_found == 1)){
return 6;
}else if(append == 1){
return 7;
}else if(redirection == 1){
return 8;
}
}
return 9;
}
//I referenced StackOverflow and some online libraries to get this tokenize function
char ** tokenize(char *str, char *delim, unsigned int *number_tokens) {
char *pch = strtok(str, delim);
unsigned int ntok = 0;
if(pch != NULL) {
ntok = 1;
}else{
return NULL;
}
char **tokens = realloc(NULL, sizeof(char *)*ntok);
tokens[ntok-1] = pch;
while(pch != NULL) {
pch = strtok(NULL, delim);
ntok++;
tokens = realloc(tokens, sizeof(char *)*ntok);
tokens[ntok-1] = pch;
}
if(number_tokens) {
*number_tokens = ntok;
}
return tokens;
}
//I referenced StackOverflow.com for this trim function
char *trim(char *str) {
char *end;
if(str == NULL){
return NULL;
}
while(isspace(*str)){
str++;
}
end = str + strlen(str) - 1;
while(end > str && isspace(*end)) {
end--;
}
*(end+1) = 0;
return str;
}
int main(int argc, char *argv[]){
int returnValue = 0;
char *infile = NULL;
char *outfile = NULL;
char **cmd = NULL;
char **cmd1_tokens = NULL;
char **cmd2_tokens = NULL;
char *input;
int current_cmd = 0;
/*
(1)If the user does not enter a command line argument, get one after typing "myshell-%"
(2)Call parse_command on the user input to get the right return value
(3)Begin parsing the user input within main
*/
if(argc == 1){
printf("myshell-%%\n");
fgets (input, 20, stdin);
returnValue = parse_command(input, cmd1_tokens, cmd2_tokens, infile, outfile);
cmd = tokenize(input, "|", NULL);
}else{
returnValue = parse_command(argv[1], cmd1_tokens, cmd2_tokens, infile, outfile);
cmd = tokenize(argv[1], "|", NULL);
}
int infileIt = 0;
while(cmd[current_cmd] != NULL) {
unsigned int number_tokens = 0;
char **infile_token = tokenize(cmd[current_cmd], "<", &number_tokens);
if(number_tokens > 1){
while(infile_token[infileIt] != NULL){
infileIt++;
}
}
if(infile_token[1] != NULL) {
number_tokens = 0;
char **infile_outfile_token = tokenize(infile_token[1], ">", &number_tokens);
if(number_tokens > 1){
infile = infile_outfile_token[0];
infile = infile_token[1];
}
}
number_tokens = 0;
char **outfile_token = tokenize(cmd[current_cmd], ">", &number_tokens);
if(number_tokens > 1){
outfile = outfile_token[1];
}
current_cmd++;
}
//Trim the in/outfiles
infile = trim(infile);
outfile = trim(outfile);
/*
Start breaking up cmd[0] and cmd[1] into smaller chunks and saving into the appropriate cmd
*/
cmd1_tokens = tokenize(cmd[0], " ", NULL);
if(cmd[1] != NULL){
cmd2_tokens = tokenize(cmd[1], " ", NULL);
}
int cmd1Args = 0;
while(cmd1_tokens[cmd1Args] != NULL){
cmd1Args++;
}
int cmd2Args= 0;
if(cmd2_tokens != NULL){
while(cmd2_tokens[cmd2Args] != NULL){
cmd2Args++;
}
}
int iterator = 0;
while((iterator < cmd1Args) && (cmd1Args != 0)){
printf("Cmd1: %s\n", cmd1_tokens[iterator]);
iterator++;
}
iterator = 0;
while((iterator < cmd2Args)&&(cmd2Args != 0)){
printf("Cmd2: %s\n", cmd2_tokens[iterator]);
iterator++;
}
if(infile != NULL){
printf("Infile: %s\n", infile);
}
if(outfile != NULL){
printf("Outfile: %s\n", outfile);
}
/*Use a switch statement to process all the return values (0 ot 9) of parse_command.
Our program should execute the âlineâ if the return code from parse_command
function is 0 to 8, that is the line is deemed âvalidâ. For return code 9,
our program simply output âNot handled at this time!â.*/
switch(returnValue){
case 0 :
printf("Exiting Program.\n");
exit(1);
break;
case 1 :
printf("Inside Case 1\n");
exec_cmd(cmd1_tokens);
break;
case 2 :
printf("Inside Case 2\n");
exec_cmd_in(cmd1_tokens, infile);
break;
case 3 :
printf("Inside Case 3\n");
exec_cmd_opt_in_append(cmd1_tokens, infile, outfile);
break;
case 4 :
printf("Inside Case 4\n");
exec_cmd_opt_in_write(cmd1_tokens, infile, outfile);
break;
case 5 :
printf("Inside Case 5\n");
exec_pipe(cmd1_tokens, cmd2_tokens);
break;
case 6 :
printf("Inside Case 6\n");
//exec_pipe_in(cmd1_tokens, cmd2_tokens, infile);
break;
case 7 :
printf("Inside Case 7\n");
exec_pipe_opt_in_append(cmd1_tokens, cmd2_tokens, infile, outfile);
break;
case 8 :
printf("Inside Case 8\n");
exec_pipe_opt_in_write(cmd1_tokens, cmd2_tokens, infile, outfile);
break;
default :
printf("Inside Case 9\n");
printf("Not handled at this time!\n");
}
return 0;
}