C shell:重定向和管道工作,但不是输入和输出重定向组合使用一个或多个管道
我的C shell可以成功处理重定向(例如,ls -al> output.txt,./pre < input1.txt,等等)和多个管道(即cmd1 | cmd 2 | cmd 3)。但是,当我尝试使用管道输入和输出重定向时,我的代码不起作用,例如./pre < input.txt | ./sort> output.txt。尽管./pre执行成功,但没有输出文件。C shell:重定向和管道工作,但不是输入和输出重定向组合使用一个或多个管道
前是打印与GPA成绩名字超过3.0
排序是按字母顺序排列的名单 input.txt的是名称和平均成绩的文件的可执行文件(名称3.1 ...)的可执行文件。
CODE:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#ifndef READ
#define READ 0
#endif
#ifndef WRITE
#define WRITE 1
#endif
void clearArgumentContainer (int argumentContainer[]);
int main() {
/* professor-supplied variables for commands and command parsing */
char *iPath, *oPath, *argv[20], buf[80], n, *p;
int m, status, inword, continu;
int start[20];
/* flags for redirection (note: C does not have type bool; using integer value 0 or 1) */
int inputRedirectFlag, outputRedirectFlag;
/* variables for piping */
int count, pipes;
pid_t pid;
/* pipes */
int l_pipe[2], r_pipe[2];
/* required container for handling arguments */
int argumentContainer[20] = { 0 };
while (1) {
inword = m = continu = count = pipes = pid = 0;
p = buf;
/* redirection flags reset */
inputRedirectFlag = outputRedirectFlag = 0;
/* shell prompt */
printf("\nshhh> ");
/* command parsing */
while ((n = getchar()) != '\n' || continu)
{
if (n == ' ') {
if (inword)
{
inword = 0;
*p++ = 0;
}
}
else if (n == '\n')
continu = 0;
else if (n == '\\' && !inword)
continu = 1;
else {
if (!inword)
{
inword = 1;
argv[m++] = p;
*p++ = n;
}
else
*p++ = n;
}
} /* end of command parsing */
*p++ = 0;
argv[m] = 0;
/* user wishes to terminate program */
if (strcmp(argv[0], "exit") == 0)
exit(0);
/* manage redirection */
while (argv[count] != 0) {
if (strcmp(argv[count], "|") == 0) {
argv[count] = 0;
argumentContainer[pipes + 1] = count + 1;
++pipes;
}
else if (strcmp(argv[count], "<") == 0) {
iPath = strdup(argv[count + 1]); /* copy string argument (file string) */
argv[count] = 0;
argv[count + 1] = 0;
inputRedirectFlag = 1;
}
else if (strcmp(argv[count], ">") == 0) {
oPath = strdup(argv[count + 1]); /* copy string argument (file string) */
argv[count] = 0;
argv[count + 1] = 0;
outputRedirectFlag = 1;
}
else {
argumentContainer[count] = count;
}
++count;
} /* end of redirection management */
/* execute commands [<= in for-loop; n pipes require n+1 processes] */
for (int index = 0; index <= pipes; ++index) {
if (pipes > 0 && index != pipes) { /* if user has entered multiple commands with '|' */
pipe(r_pipe); /* no pipe(l_pipe); r_pipe becomes next child's l_pipe */
}
/* switch-statement for command execution */
switch (pid = fork()) {
/* fork() error */
case -1: perror("fork failed");
break;
case 0: /* child process manages redirection and executes */
if ((index == 0) && (inputRedirectFlag == 1)) {
int inputFileDescriptor = open(iPath, O_RDONLY , 0400);
if (inputFileDescriptor == -1) {
perror("input file failed to open\n");
return(EXIT_FAILURE);
}
close(READ);
dup(inputFileDescriptor);
close(inputFileDescriptor);
} /* end of input redirection management */
if ((index == pipes) && (outputRedirectFlag == 1)) {
int outputFileDescriptor = open(oPath, O_WRONLY | O_CREAT, 0755);
if (outputFileDescriptor < 0) {
perror("output file failed to open\n");
return(EXIT_FAILURE);
}
close(WRITE);
dup(outputFileDescriptor);
close(outputFileDescriptor);
} /* end of output redirection management */
/* manage pipes if (a) first child process, (b) middle child process, or (c) third/final child process */
if (pipes > 0) {
if (index == 0){ /* first child process */
close(WRITE);
dup(r_pipe[WRITE]);
close(r_pipe[WRITE]);
close(r_pipe[READ]);
}
else if (index < pipes) { /* middle child process */
close(READ);
dup(l_pipe[READ]);
close(l_pipe[READ]);
close(l_pipe[WRITE]);
close(WRITE);
dup(r_pipe[WRITE]);
close(r_pipe[READ]);
close(r_pipe[WRITE]);
}
else { /* third/final child process */
close(READ);
dup(l_pipe[READ]);
close(l_pipe[READ]);
close(l_pipe[WRITE]);
}
}
/* execute command */
execvp(argv[argumentContainer[index]], &argv[argumentContainer[index]]);
/* if execvp() fails */
perror("execution of command failed\n");
break;
default: /* parent process manages the pipes for child process(es) */
if (index > 0) {
close(l_pipe[READ]);
close(l_pipe[WRITE]);
}
l_pipe[READ] = r_pipe[READ];
l_pipe[WRITE] = r_pipe[WRITE];
/* parent waits for child process to complete */
wait(&status);
break;
} /* end of switch-statement for command execution */
} /* end of loop for all pipes */
// clear all executed commands
for (int i = 0; i < 20; ++i) {
argv[i] = 0;
}
}
}
void clearArgumentContainer (int argumentContainer[]){
// clear argument container
for (int i = 0; i < 20; ++i) {
argumentContainer[i] = 0;
}
}
这里是我使用的输入文件:
Tim 3.5
Todd 2.1
Beth 3.9
Jason 3.5
Zander 3.3
Alex 3.5
Tyler 3.5
Lauren 3.6
Jack 2.3
Amir 3.4
Beth 3.2
预可执行文件将只列出比3.0 排序可执行更高的GPA将整理名称列表这些名字按字母顺序排列
这是我的最终工作代码。它不像cd那样实现内置插件,但我打算很快实现这些内置插件!计划确实符合作业的要求。
我的重大变化发生在重定向处理。我不得不删除一行代码在两个地方:
argv[count + 1] = 0;
从重定向“<”和“>”。
我还添加了处理管道连接的代码,无论我的过程是第一个孩子,最后一个还是介于两者之间。
代码:
/***********************************************************************************************
***********************************************************************************************
Student: Douglas Adolph
Course: Operating Systems
Project #: 2
Program emulates shell, and can do the following:
1. Can execute a command with the accompanying arguments.
2. Recognize multiple pipe requests and handle them.
3. Recognize redirection requests and handle them.
4. Type "exit" to quit the shhh shell.
Notes:
Shell built-ins (cd, echo, etc.) not yet implemented
REFERENCED:
1. http://www.thinkplexx.com/learn/article/unix/command
2. http://man7.org/linux/man-pages/man2/open.2.html
3. https://*.com/questions/19846272/redirecting-i-o-implementation-of-a-shell-in-c
**********************************************************************************************
*********************************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#ifndef READ
#define READ 0
#endif
#ifndef WRITE
#define WRITE 1
#endif
void clearArgIndexContainer (int argLocation[]);
int main() {
/* variables for command parsing and storage*/
char n, *parser, buf[80], *argv[20];
int m, status, inword, continu;
/* variables and flags for redirection (note: C does not have type bool; using integer value 0 or 1) */
char *in_path, *out_path;
int inputRedirectFlag, outputRedirectFlag;
/* variables for piping */
int count, pipes;
pid_t pid;
/* left and right pipes */
int l_pipe[2], r_pipe[2];
/* container for recording argument locations in argv[] */
int argLocation[20] = { 0 };
while (1) {
/* reset parsing and piping variable values */
m = inword = continu = count = pipes = pid = 0;
/* begin parsing at beginning of buffer */
parser = buf;
/* reset redirection flags */
inputRedirectFlag = outputRedirectFlag = 0;
/* print shell prompt */
printf("\nshhh> ");
/* parse commands */
while ((n = getchar()) != '\n' || continu)
{
if (n == ' ') {
if (inword)
{
inword = 0;
*parser++ = 0;
}
}
else if (n == '\n')
continu = 0;
else if (n == '\\' && !inword)
continu = 1;
else {
if (!inword)
{
inword = 1;
argv[m++] = parser;
*parser++ = n;
}
else
*parser++ = n;
}
} /* end of command parsing */
/* append terminating character to end of parser buffer and argv buffer */
*parser++ = 0;
argv[m] = 0;
/* user wishes to terminate program */
if (strcmp(argv[0], "exit") == 0)
exit(0);
/* manage redirection */
while (argv[count] != 0) {
if (strcmp(argv[count], "|") == 0) {
argv[count] = 0;
argLocation[pipes + 1] = count + 1;
++pipes;
}
else if (strcmp(argv[count], "<") == 0) {
in_path = strdup(argv[count + 1]);
argv[count] = 0;
inputRedirectFlag = 1;
}
else if (strcmp(argv[count], ">") == 0) {
out_path = strdup(argv[count + 1]);
argv[count] = 0;
outputRedirectFlag = 1;
}
else {
argLocation[count] = count;
}
++count;
} /* end of redirection management */
/* execute commands [<= in for-loop; n pipes require n+1 processes] */
for (int index = 0; index <= pipes; ++index) {
if (pipes > 0 && index != pipes) { /* if user has entered multiple commands with '|' */
pipe(r_pipe); /* no pipe(l_pipe); r_pipe becomes next child's l_pipe */
}
/* switch-statement for command execution */
switch (pid = fork()) {
case -1: perror("fork failed"); /* fork() error */
break;
case 0: /* child process manages redirection and executes */
if ((index == 0) && (inputRedirectFlag == 1)) {
int inputFileDescriptor = open(in_path, O_RDONLY , 0400);
if (inputFileDescriptor == -1) {
perror("input file failed to open\n");
return(EXIT_FAILURE);
}
close(READ);
dup(inputFileDescriptor);
close(inputFileDescriptor);
} /* end of input redirection management */
if ((index == pipes) && (outputRedirectFlag == 1)) {
//printf("DEBUG: here we should be about to create our output file\n");
int outputFileDescriptor = creat(out_path, 0700);
if (outputFileDescriptor < 0) {
perror("output file failed to open\n");
return(EXIT_FAILURE);
}
close(WRITE);
dup(outputFileDescriptor);
close(outputFileDescriptor);
} /* end of output redirection management */
/* manage pipes if (a) first child process, (b) in-between child process, or (c) final child process */
if (pipes > 0) {
if (index == 0){ /* first child process */
close(WRITE);
dup(r_pipe[WRITE]);
close(r_pipe[WRITE]);
close(r_pipe[READ]);
}
else if (index < pipes) { /* in-between child process */
close(READ);
dup(l_pipe[READ]);
close(l_pipe[READ]);
close(l_pipe[WRITE]);
close(WRITE);
dup(r_pipe[WRITE]);
close(r_pipe[READ]);
close(r_pipe[WRITE]);
}
else { /* final child process */
close(READ);
dup(l_pipe[READ]);
close(l_pipe[READ]);
close(l_pipe[WRITE]);
}
}
/* execute command */
execvp(argv[argLocation[index]], &argv[argLocation[index]]);
/* if execvp() fails */
perror("execution of command failed\n");
break;
default: /* parent process manages the pipes for child process(es) */
if (index > 0) {
close(l_pipe[READ]);
close(l_pipe[WRITE]);
}
l_pipe[READ] = r_pipe[READ];
l_pipe[WRITE] = r_pipe[WRITE];
/* parent waits for child process to complete */
wait(&status);
break;
} /* end of switch-statement for command execution */
} /* end of loop for all pipes */
// clear all executed commands
for (int i = 0; i < 20; ++i) {
argv[i] = 0;
}
}
}
void clearArgIndexContainer (int argLocation[]){
// clear argument container
for (int i = 0; i < 20; ++i) {
argLocation[i] = 0;
}
}
这是我除去制作的argv线[计数+ 1] = 0; :
/* manage redirection */
while (argv[count] != 0) {
if (strcmp(argv[count], "|") == 0) {
argv[count] = 0;
argLocation[pipes + 1] = count + 1;
++pipes;
}
else if (strcmp(argv[count], "<") == 0) {
in_path = strdup(argv[count + 1]);
argv[count] = 0;
inputRedirectFlag = 1;
}
else if (strcmp(argv[count], ">") == 0) {
out_path = strdup(argv[count + 1]);
argv[count] = 0;
outputRedirectFlag = 1;
}
else {
argLocation[count] = count;
}
这是我的专业除了处理到管道:
/* manage pipes if (a) first child process, (b) in-between child process, or (c) final child process */
if (pipes > 0) {
if (index == 0){ /* first child process */
close(WRITE);
dup(r_pipe[WRITE]);
close(r_pipe[WRITE]);
close(r_pipe[READ]);
}
else if (index < pipes) { /* in-between child process */
close(READ);
dup(l_pipe[READ]);
close(l_pipe[READ]);
close(l_pipe[WRITE]);
close(WRITE);
dup(r_pipe[WRITE]);
close(r_pipe[READ]);
close(r_pipe[WRITE]);
}
else { /* final child process */
close(READ);
dup(l_pipe[READ]);
close(l_pipe[READ]);
close(l_pipe[WRITE]);
}
}
我还有更多的工作要做,即实现内置插件,也把更多的这种成单独的功能清理代码并使其更具可读性。对于某些可能写得更好的表达方式,我也给了一些很好的建议,我很快就会解决这个问题。
良好的工作。建议您初始化'char * in_path = NULL,* out_path = NULL;'和'int l_pipe [2] = {0},r_pipe [2] = {0};'消除初始化警告。 –
评论不适用于扩展讨论;这个对话已经[转移到聊天](http://chat.*.com/rooms/156760/discussion-on-question-by-douglas-adolph-c-shell-redirection-and-piping-working)。 – Andy