У меня много проблем с заданием для школы. Я должен добавить каналы и перенаправление ввода-вывода к реализации оболочки в c. Я уже получил его для работы с перенаправлением ввода-вывода, и сами трубы работают, но мне нужно поддерживать что-то вроде этого «sort < file.txt | grep main | cat> output». Я не знаю, как заставить его работать одновременно. Любая помощь будет с благодарностью оценена.Реализация оболочки с трубками и перенаправление I O в c
int get_args(char* cmdline, char* args[]){
int i = 0;
/* if no args */
if((args[0] = strtok(cmdline, "\n\t ")) == NULL)
return 0;
while((args[++i] = strtok(NULL, "\n\t ")) != NULL) {
if(i >= MAX_ARGS) {
printf("Too many arguments!\n");
exit(1);
}
}
/* the last one is always NULL */
return i;
}
void pipehandler(char* args[], int nargs){
int num_cmds = 0;
char *command[256];
int filedes[2]; // pos. 0 output, pos. 1 input of the pipe
int filedes2[2];
int i = 0;
//calculate the number of commands
for(int i = 0; i < nargs; i++){
if (strcmp(args[i], "|") == 0){
num_cmds++;
}
}
num_cmds++;
if(num_cmds <= 1){
return;
}
int j = 0;
int end = 0;
pid_t pid;
while(args[j] != NULL && end != 1){
int k = 0;
while (strcmp(args[j],"|") != 0){
command[k] = args[j];
j++;
if (args[j] == NULL){
// 'end' variable used to keep the program from entering
// again in the loop when no more arguments are found
end = 1;
k++;
break;
}
k++;
}
// Last position of the command will be NULL to indicate that
// it is its end when we pass it to the exec function
command[k] = NULL;
j++;
// Depending on whether we are in an iteration or another, we
// will set different descriptors for the pipes inputs and
// output. This way, a pipe will be shared between each two
// iterations, enabling us to connect the inputs and outputs of
// the two different commands.
if (i % 2 != 0){
pipe(filedes); // for odd i
}else{
pipe(filedes2); // for even i
}
pid=fork();
if(pid==-1){
if (i != num_cmds - 1){
if (i % 2 != 0){
close(filedes[1]); // for odd i
}else{
close(filedes2[1]); // for even i
}
}
printf("Child process could not be created\n");
return;
}
if(pid==0){
// If we are in the first command
if (i == 0){
dup2(filedes2[1], STDOUT_FILENO);
}
// If we are in the last command, depending on whether it
// is placed in an odd or even position, we will replace
// the standard input for one pipe or another. The standard
// output will be untouched because we want to see the
// output in the terminal
else if (i == num_cmds - 1){
if (num_cmds % 2 != 0){ // for odd number of commands
dup2(filedes[0],STDIN_FILENO);
}else{ // for even number of commands
dup2(filedes2[0],STDIN_FILENO);
}
// If we are in a command that is in the middle, we will
// have to use two pipes, one for input and another for
// output. The position is also important in order to choose
// which file descriptor corresponds to each input/output
}else{ // for odd i
if (i % 2 != 0){
dup2(filedes2[0],STDIN_FILENO);
dup2(filedes[1],STDOUT_FILENO);
}else{ // for even i
dup2(filedes[0],STDIN_FILENO);
dup2(filedes2[1],STDOUT_FILENO);
}
}
execvp(command[0],command);
}
// CLOSING DESCRIPTORS ON PARENT
if (i == 0){
close(filedes2[1]);
}
else if (i == num_cmds - 1){
if (num_cmds % 2 != 0){
close(filedes[0]);
}else{
close(filedes2[0]);
}
}else{
if (i % 2 != 0){
close(filedes2[0]);
close(filedes[1]);
}else{
close(filedes[0]);
close(filedes2[1]);
}
}
waitpid(pid,NULL,0);
i++;
}
}
int searchIO(char* args[], int *nargs, char** input_file, char** output_file, int* in, int* out, int* ap){
int ioRedirection = -1;
//search through the array args
printf("searching for io redirections\n");
for(int i = 0; i < *nargs; i++){
if(strcmp(args[i], "<") == 0){
//if you find < then you need to redirect the stdin to be from a file
//if you are here then the input file is in args[i+1]
*input_file = args[i+1];
printf("this is the input file %s \n", *input_file);
//we need to remove the < and input_file from args[]
int j;
for(j = i; j < *nargs; j++){
//move what is in args[j+2] to args[j];
args[j] = args[j+2];
}
//then we need to execute the comand
*nargs = *nargs-2;
*in = 1;
i = 0;
ioRedirection = 1;
}else if (strcmp(args[i], ">") == 0){
//if you are here then the output file is in args[i+1]
//so aparently execute what is in args[0] to args[i]
*output_file = args[i+1];
//we need to remove the > and output_file from args[]
int j;
for(j = i; j < *nargs; j++){
//move what is in args[j+2] to args[j];
if(j < *nargs){
args[j] = args[j+2];
}
}
*nargs = *nargs-2;
*out = 1;
i = 0;
ioRedirection = 1;
}else if (strcmp(args[i], ">>") == 0){
//if you are here then the output file is in args[i+1]
//so aparently execute what is in args[0] to args[i]
*output_file = args[i+1];
//we need to remove the > and output_file from args[]
int j;
for(j = i; j < *nargs; j++){
//move what is in args[j+2] to args[j];
args[j] = args[j+2];
}
*nargs = *nargs-2;
*out = 1;
*ap = 1;
i = 0;
ioRedirection = 1;
}
}
return -1;
}
void execute(char* cmdline){
int pid, async;
char* args[MAX_ARGS];
char *input_file;
char *output_file;
int _in, _out, _ap;
_in = 0;
_out = 0;
_ap = 0;
int nargs = get_args(cmdline, args);
pipehandler(args, nargs);
searchIO(args, &nargs, &input_file, &output_file, &_in, &_out, &_ap);
if(nargs <= 0) return;
if(!strcmp(args[0], "quit") || !strcmp(args[0], "exit")) {
exit(0);
}
if(!strcmp(args[nargs-1], "&")) { async = 1; args[--nargs] = 0; }
else async = 0;
pid = fork();
if(pid == 0) { /* child process */
if(_in == 1){
int input = open(input_file, O_RDONLY);
dup2(input, STDIN_FILENO);
close(input);
}
if(_out == 1){
int output;
if(_ap){
output = open(output_file, O_APPEND | O_CREAT);
}else{
output = open(output_file, O_CREAT | O_WRONLY, 0666);
}
dup2(output, STDOUT_FILENO);
close(output);
}
execvp(args[0], args);
/* return only when exec fails */
perror("exec failed");
exit(-1);
} else if(pid > 0) { /* parent process */
if(!async) waitpid(pid, NULL, 0);
else printf("this is an async call\n");
} else { /* error occurred */
perror("fork failed");
exit(1);
}
}
int main (int argc, char* argv [])
{
char cmdline[BUFSIZ];
for(;;) {
printf("$ ");
if(fgets(cmdline, BUFSIZ, stdin) == NULL) {
perror("fgets failed");
exit(1);
}
execute(cmdline) ;
}
return 0;
}
Не полный ответ, так как это домашнее задание, но для поддержки перенаправления с помощью '|' вам нужно «fork» более одного раза, подключая выходной канал каждой программы к входному каналу следующего. Если в конце есть '>', вам нужно открыть файл и перенаправить на него вывод последнего этапа. – Davislor
Посмотрите на http://stackoverflow.com/questions/3930339/implementing-pipes-in-ac-shell-unix?rq=1 – MrKiwi
, если используются трубы, единственное место для использования перенаправления ввода-вывода находится в первая команда и в последнем, но не в середине справа? – tommy