在我的一个课程中,我们正在编写自己的shell(基本上是从头开始)。
我们已经处理过编写词法分析器和解析器来将输入划分为更容易处理的漂亮“命令”结构。同样,我有一个函数read_command()
,它将一次读取一个命令,并确定它是什么类型的命令(管道/和/或/简单/等)。
我现在正在尝试编写实际接受命令并运行它的execute_command(struct command cmd)
函数。我正在努力学习如何开始实际编写这个函数。
假设我得到一个非常简单的cat foo.txt
作为命令。我的命令结构将它整齐划分,所以我有一个单词数组,其中包含两个单词。
现在我想使用参数cat
运行foo.txt
可执行文件。我意识到我应该使用$PATH
变量来尝试查找可执行文件,然后使用此参数运行它。
我正在努力解决几个主要问题:
cat
?请记住,该程序使用C.我可以使用哪些功能搜索目录?如何使用PATH执行此操作?cat
时,如何以foo.txt
作为参数运行它?如何在C中完成?答案 0 :(得分:11)
getenv(3)
及其亲属。您可能实际上不需要直接对目录执行任何操作,但如果这样做,您可以使用opendir(3)
,readdir(3)
,closedir(3)
等。fork(2)
和execl(3)
或其中一位亲属(execve(2)
是基础API)。手册本身或简单的谷歌搜索任何这些功能将提供大量的例子来帮助你。
答案 1 :(得分:4)
将命令字符串拆分为单独的字符串(命令名称,参数),然后将它们存储在以空字符结尾的字符指针数组中。然后,您将命令名称和命令+参数传递给execvp()
,除非这是禁止的。你最终还是要担心管道和I / O重定向,但基本的想法仍然是一样的。
char *args[MAXARGS];
args[0] = "cat";
args[1] = "foo.txt";
args[2] = 0;
if ((pid = fork()) == 0)
{
execvp(args[0], args);
...print error...
exit(1);
/* execvp() does not return unless there's an error */
}
else if (pid < 0)
...fork failed...
else
...wait for child to finish - or start other commands, or ...
您可以在真实的shell中动态分配args
。如果必须为执行的程序提供自定义环境,则会更加困难。基本上,您将组装环境的副本,然后在分叉后,将全局environ
设置为新值 - 但如果新环境包含PATH的新值,则会影响对命令的搜索按execvp()
。因此,您最终可能会编写自己的execvp()
变体。如果是这样的话,请从BSD(MacOS X)书中取出一页;有一个函数execvP()
:
int execvP(const char *file, const char *search_path, char *const argv[]);
允许您指定要使用的搜索路径,即使您已修复了环境。最根本的呼吁是execve()
;这在幕后execvp()
使用(可能通过execv()
)。