gpt4 book ai didi

c - 在 c 中使用管道和 I\O 重定向的 Shell 实现

转载 作者:太空宇宙 更新时间:2023-11-04 04:26:30 25 4
gpt4 key购买 nike

我在学校作业上遇到了很多麻烦。我应该将管道和 I/O 重定向添加到 c 中的 shell 实现中。我已经让它与 I/O 重定向一起工作并且管道自己工作但我需要支持这样的东西“sort < file.txt | grep main | cat > output”。我不知道如何让它同时与两者一起工作。任何帮助将不胜感激。

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;
}

最佳答案

if pipes are being used the only place to use I/O redirections is in the first command and in the last one but not in the middle right?

只有当 stdin/stdout 被重定向时,这才是正确的。

I/O redirections and the pipes work by themselves but … I have no idea how to make it work with both at the same time.

重组您的实现。如果你调用它就不能工作

 pipehandler(args, nargs);
searchIO(args, &nargs, &input_file, &output_file, &_in, &_out, &_ap);

一个接一个,这也导致管道的第一个命令被执行两次的错误(首先来自 pipehandler,然后来自 searchIO,参数错误)。相反,您可以让 main 调用 pipehandler,然后从 pipehandler执行每个单独的命令(即使有只有一个,没有管道)。可以轻松诊断冲突的 I/O 重定向和管道。

关于c - 在 c 中使用管道和 I\O 重定向的 Shell 实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40925272/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com