阅读器。我正在编写一个模仿linux shell的C程序。在实现管道之前,我的代码正常工作,并且在输出/输入文件上。接下来是实现诸如(a | b)| c的命令管道。以下是我的代码:
测试它,我得到“sfhjdj”,“exit”和“cd”的正确返回。我遇到的问题是运行一个简单的命令会返回ls: write error: Bad file descriptor
。尝试管道只运行第一个功能。是什么导致这个?正如我从其他问题中看到的那样,我试图管道。
下面是我在实现管道之前的代码,我找不到错误,但可能是因为关闭/重复。感谢您阅读本文!
仅在执行功能中进行了更改。
编辑:帮助程序代码,prase.c
/*
* parse.c - feeble command parsing for the Feeble SHell.
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "parse.h"
#include "error.h"
#define MAXARGV 1000
enum token {
identifier, directin, directout, doubledirectout,
/* everything >= semicolon ends an individual "struct pipeline" */
semicolon,
ampersand,
verticalbar, doubleampersand, doublebar, doublepipe,
eol
};
static enum token gettoken(char **s, char **argp);
static char *ptok(enum token tok);
struct parsed_line *parse(char *s)
{
struct parsed_line *retval; /* remains freeparse()able at all times */
struct parsed_line *curline;
struct pipeline **plp; /* where to append for '|' and '|||' */
char *argv[MAXARGV];
enum token tok;
int argc = 0;
int isdouble = 0;
retval = curline = emalloc(sizeof(struct parsed_line));
curline->conntype = CONN_SEQ; /* i.e. always do this first command */
curline->inputfile = curline->outputfile = NULL;
curline->output_is_double = 0;
curline->isbg = 0;
curline->pl = NULL;
curline->next = NULL;
plp = &(curline->pl);
do {
if (argc >= MAXARGV)
fatal("argv limit exceeded");
while ((tok = gettoken(&s, &argv[argc])) < semicolon) {
switch ((int)tok) { /* cast prevents stupid warning message about
* not handling all enum token values */
case identifier:
argc++; /* it's already in argv[argc];
* increment to represent a save */
break;
case directin:
if (curline->inputfile) {
fprintf(stderr,
"syntax error: multiple input redirections\n");
freeparse(curline);
return(NULL);
}
if (gettoken(&s, &curline->inputfile) != identifier) {
fprintf(stderr, "syntax error in input redirection\n");
freeparse(curline);
return(NULL);
}
break;
case doubledirectout:
curline->output_is_double = 1;
/* fall through */
case directout:
if (curline->outputfile) {
fprintf(stderr,
"syntax error: multiple output redirections\n");
freeparse(curline);
return(NULL);
}
if (gettoken(&s, &curline->outputfile) != identifier) {
fprintf(stderr, "syntax error in output redirection\n");
freeparse(curline);
return(NULL);
}
break;
}
}
/* cons up just-parsed pipeline component */
if (argc) {
*plp = emalloc(sizeof(struct pipeline));
(*plp)->next = NULL;
(*plp)->argv = eargvsave(argv, argc);
(*plp)->isdouble = isdouble;
plp = &((*plp)->next);
isdouble = 0;
argc = 0;
} else if (tok != eol) {
fprintf(stderr, "syntax error: null command before `%s'\n",
ptok(tok));
freeparse(curline);
return(NULL);
}
/* ampersanded? */
if (tok == ampersand)
curline->isbg = 1;
/* is this a funny kind of pipe (to the right)? */
if (tok == doublepipe)
isdouble = 1;
/* does this start a new struct parsed_line? */
if (tok == semicolon || tok == ampersand || tok == doubleampersand || tok == doublebar) {
curline->next = emalloc(sizeof(struct parsed_line));
curline = curline->next;
curline->conntype =
(tok == semicolon || tok == ampersand) ? CONN_SEQ
: (tok == doubleampersand) ? CONN_AND
: CONN_OR;
curline->inputfile = curline->outputfile = NULL;
curline->output_is_double = 0;
curline->isbg = 0;
curline->pl = NULL;
curline->next = NULL;
plp = &(curline->pl);
}
} while (tok != eol);
return(retval);
}
/* (*s) is advanced as we scan; *argp is set iff retval == identifier */
static enum token gettoken(char **s, char **argp)
{
char *p;
while (**s && isascii(**s) && isspace(**s))
(*s)++;
switch (**s) {
case '\0':
return(eol);
case '<':
(*s)++;
return(directin);
case '>':
(*s)++;
if (**s == '&') {
(*s)++;
return(doubledirectout);
}
return(directout);
case ';':
(*s)++;
return(semicolon);
case '|':
if ((*s)[1] == '|') {
*s += 2;
return(doublebar);
}
(*s)++;
if (**s == '&') {
(*s)++;
return(doublepipe);
}
return(verticalbar);
case '&':
if ((*s)[1] == '&') {
*s += 2;
return(doubleampersand);
} else {
(*s)++;
return(ampersand);
}
/* else identifier */
}
/* it's an identifier */
/* find the beginning and end of the identifier */
p = *s;
while (**s && isascii(**s) && !isspace(**s) && !strchr("<>;&|", **s))
(*s)++;
*argp = estrsavelen(p, *s - p);
return(identifier);
}
static char *ptok(enum token tok)
{
switch (tok) {
case directin:
return("<");
case directout:
return(">");
case semicolon:
return(";");
case verticalbar:
return("|");
case ampersand:
return("&");
case doubleampersand:
return("&&");
case doublebar:
return("||");
case doubledirectout:
return(">&");
case doublepipe:
return("|&");
case eol:
return("end of line");
default:
return(NULL);
}
}
static void freepipeline(struct pipeline *pl)
{
if (pl) {
char **p;
for (p = pl->argv; *p; p++)
free(*p);
free(pl->argv);
freepipeline(pl->next);
free(pl);
}
}
void freeparse(struct parsed_line *p)
{
if (p) {
freeparse(p->next);
if (p->inputfile)
free(p->inputfile);
if (p->outputfile)
free(p->outputfile);
freepipeline(p->pl);
free(p);
}
Builtin.c - 用于cd并退出
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "fsh.h"
#include "builtin.h"
int builtin_exit(char **argv)
{
if (argv[1] && argv[2]) /* i.e. argc >= 2 */ {
fprintf(stderr, "usage: exit [status]\n");
fflush(stderr);
return(1);
} else if (argv[1]) {
/* "exit ###" */
exit(atoi(argv[1]));
} else {
/* "exit" with no argument */
exit(laststatus);
}
}
int builtin_cd(char **argv)
{
if (argv[1] && argv[2]) {
fprintf(stderr, "usage: %s dir\n", argv[0]);
return(1);
} else if (argv[1]) {
chdir(argv[1]);
} else {
chdir(getenv("HOME"));
}
//if (chdir(argv[1])) {
// perror(argv[1]);
// return(1);
//}
return(0);
}
Parse.h - 管道是怎样的
enum connenum {
CONN_SEQ, /* sequential commands, i.e. separated by a semicolon */
CONN_AND, /* commands joined by '&&' */
CONN_OR /* commands joined by '||' */
};
struct pipeline { /* list of '|'-connected commands */
char **argv; /* array ending with NULL */
struct pipeline *next; /* NULL if this doesn't pipe into anything */
int isdouble; /* 1 if we have '|&' i.e. should dup onto 2 */
};
struct parsed_line { /* list of ';' or '&&' or '||' -connected struct pipelines */
enum connenum conntype; /* will be CONN_SEQ if this is the first item */
char *inputfile, *outputfile; /* NULL for no redirection */
int output_is_double; /* output redirection is '>&' rather than '>' */
struct pipeline *pl; /* the command(s) */
int isbg; /* non-zero iff there is a '&' after this command */
struct parsed_line *next; /* connected as specified by next->conntype */
};
extern struct parsed_line *parse(char *s);
extern void freeparse(struct parsed_line *p);
答案 0 :(得分:1)
如果你真的想要了解煤炭,可以帮助你。
如果您更喜欢使用 popen
,这可能对您有所帮助参考 Pipes the Easy Way using popen
我测试了这个,它可以做你想要的事情例如打开2个管道(ls和sort命令)注意 popen中的r属性(&#34; ls&#34;,&#34; r&#34;)我怀疑可能是上述代码的问题。
例如
如果父级想要接收来自孩子的数据,则关闭fd1 ,并且孩子关闭fd0 。如果父级要向子级发送数据,则关闭fd0 ,,子级应关闭fd1 。
由于父母和孩子之间共享描述符,我们应该始终确保关闭我们并不关心的管道末尾。从技术角度来说,如果未明确关闭管道的不必要的末端,则永远不会返回EOF。
管道的文件描述符可能未设置为读取 / 写入或文件描述符按正确的顺序关闭..
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE *pipein_fp, *pipeout_fp;
char readbuf[80];
/* Create one way pipe line with call to popen() */
if (( pipein_fp = popen("ls", "r")) == NULL)
{
perror("popen");
exit(1);
}
/* Create one way pipe line with call to popen() */
if (( pipeout_fp = popen("sort", "w")) == NULL)
{
perror("popen");
exit(1);
}
/* Processing loop */
while(fgets(readbuf, 80, pipein_fp))
fputs(readbuf, pipeout_fp);
/* Close the pipes */
pclose(pipein_fp);
pclose(pipeout_fp);
return(0);
}
如果您需要Parsing Program Arguments
• Getopt:使用getopt解析程序选项。
• Argp:使用argp_parse解析程序选项。
•子选项:某些程序需要更详细的选项。
可以帮助你。
一切顺利