我正在用C语言编写一个unix minishell,而且我正在添加命令扩展。我的意思是我可以在其他命令中嵌套命令,例如:
$> echo hello $(echo world! ... $(echo and stuff))
hello world! ... and stuff
我认为我主要使用它,但它没有正确标记扩展字符串的结尾,例如,如果我这样做:
$> echo a $(echo b $(echo c))
a b c
$> echo d $(echo e)
d e c
看到它打印c,即使我没有要求它。这是我的代码:
msh.c - http://pastebin.com/sd6DZYwB expand.c - http://pastebin.com/uLqvFGPw
我有更多的代码,但有很多代码,这些是我目前遇到的问题。我会试着告诉你我这样做的基本方法。
Main在msh.c中,这里它从命令行或shellfile获取一行输入,然后调用processline(char * line,int outFD,int waitFlag),其中line是我们刚刚得到的行, outFD是输出文件的文件描述符,waitFlag告诉我们是否应该等待fork。当我们从main调用它时,我们这样做:
processline (buffer, 1, 1);
在流程线中,我们分配一个新行:
char expanded_line[EXPANDEDLEN];
然后我们在expand.c中调用expand:
expand(line, expanded_line, EXPANDEDLEN);
在展开中,我们将字符从字面上复制到expanded_line,直到我们找到$(,然后调用:
static int expCmdOutput(char *orig, char *new, int *oldl_ind, int *newl_ind)
orig是line,new是扩展行。 oldl_ind和newl_ind分别是行和扩展行中的当前位置。然后我们管道,并递归调用processline,传递嵌套命令(例如,如果我们有“echo a $(echo b)”,我们将传递processline“echo b”)。
这是我感到困惑的地方,每次调用expand时,它是否分配了一大块内存EXPANDEDLEN?如果是这样,这很糟糕,因为我会很快耗尽堆栈空间(在嵌入式命令行输入非常大的情况下)。在展开中,我在展开的字符串的末尾插入一个空字符,那么为什么要打印它呢?
如果你们需要更多的代码或解释,请问。其次,我把代码放在pastebin中,因为它有很多,而且根据我的经验,当我用代码填充几页时,人们不喜欢它。
答案 0 :(得分:1)
你的问题在于expCmdOutput
。正如您已经注意到的那样,在使用read
读取子进程的输出时,您不会获得NUL终止字符串。你想要做的是手动终止字符串,添加类似
buf[bytes_read] = '\0';
在第29行(expand.c)中致电read
之后。你需要NUL空间,你当然只能读取BUF_SIZE - 1
个字节。
你应该重新思考之后你做的整个循环,但是:
/* READ OUTPUT OF COMMAND FROM READ END OF PIPE, THEN CLOSE READ END */
bytes_read = read(fd[0],buf,BUF_SIZE);
while(bytes_read > 0)
{
bytes_read = read(fd[0], buf, BUF_SIZE);
if (bytes_read == -1) perror("read");
}
close(fd[0]);
如果命令的输出长于BUF_SIZE,则只需再次读取buf
,覆盖刚刚读取的输出。你真正想要的是分配内存并使用strcat
追加到最后(或者通过指向字符串末尾的指针来提高效率)。