4

我正在用 C 编写自己的 shell。它需要能够显示用户当前目录,根据完整路径执行命令(必须使用 execv),并允许用户使用 cd 更改目录。

这是作业。老师只给了我们关于 C 的基本入门知识和关于程序应该如何工作的非常简短的框​​架。由于我不是一个容易放弃的人,我已经研究了三天如何做到这一点,但现在我很难过。

这是我到目前为止所拥有的:

  • 显示用户的用户名、计算机名和当前目录(默认为主目录)。
  • 提示用户输入,并获取输入
  • 将用户的输入按“”拆分为参数数组
  • 通过“:”将环境变量 PATH 拆分为令牌数组

我不知道如何从这里开始。我知道我必须使用 execv 命令,但在我对谷歌的研究中,我还没有真正找到我理解的示例。例如,如果命令是 bin/ls,那么 execv 如何知道显示主目录中的所有文件/文件夹?如何告诉系统我更改了目录?

我一直在使用这个网站,这很有帮助: http: //linuxgazette.net/111/ramankutty.html但我又一次被难住了。

谢谢你的帮助。让我知道是否应该发布一些现有代码,但我不确定是否有必要。

4

4 回答 4

1

例如,如果命令是bin/ls,如何execv知道显示主目录中的所有文件/文件夹?如何告诉系统我更改了目录?

每个进程都有一个当前工作目录,可以使用chdir. 子进程将从其父进程继承工作目录。cd因此,通常您的 shell 将根据用户输入的命令来管理其当前工作目录。当输入一个非内置命令时,您将fork创建一个子进程,然后调用execv那里执行二进制文件。

If you ant to take the PATH into account for program names that contain no directory part, then you should try all possible combinations of a PATH element and the program name. You can either check whether the named file does exist, or simply try to execute it and continue with the next if that fails. If all execv calls failed, you will have to call _exit in order to terminate the child process.

Note that most shells will treat any command which contains a / as a path which gets passed to execv directly. If the path does not start with a /, then it is a relative path, and the operating system will resolve it with respect to the current working directory. In other words, the bin/ls from your example would refer to the ls binary in the bin directory which is a subdirectory of the current working directory. Only commands which do not contain any / at all are either interpreted as a builtin command (like cd) or the name of some binary located on the PATH.

The first argument to execv is the path as you computed it. The first element of the argv list traditionally equals the name as it was enetered, i.e. without an added PATH directory. After that first argument, any additional command line parameters are passed, followed by a NULL to terminate the list.

于 2012-09-29T09:35:54.677 回答
1

To implement the cd command you just need the system call chdir.

#include <unistd.h>

int chdir(
    const char *path /* the path name */
);

So you can just call something like:

int ret1 = chdir("../foo/bar");

The return value of chdir is 0 when it was possible to change into that directory and -1 if an error occurred. For the error you should consolidate the man page.

The current directory can be checked by any program, so if you execute ls without any arguments, then ls checks in which directory it is running and uses this directory as the only argument. This is a feature of ls and not of the execv call.

For the second part.

#include <unistd.h>
int execv(
     const char *path, /* programm path*/
     char *const argv[]/* argument vector*/
);

execv executes a executable file at the given path and with the arguments given in argv. So if you want to execute /bin/ls ../foo /bar, you need something similar to

char *cmd_str = "/bin/ls";
char *argv[] = {cmd_str, "../foo", "/bar", NULL };
if (execv(cmd_str, argv) == -1 ){
    /* an error occurred */
}

The error returned by execv is -1. If you want to know why it did not execute the comand check out the man pages.

The NULL in char *argv[] = {cmd_str, "../foo", "/bar", NULL }; is there to indicate that there are no other arguments after the NULL.

The third part. Unix based system normally treat commands with a / in it as commands that can be executed directly. Which means you first check if there is a slash in the given command string.

int ret_value;
if (strchr(cmd_str, '/')
    if (execv(cmd_str, argv) == -1 ){
        /* an error occurred */
    }

If there is no slash then you need to go through all directories in PATH and check if you can execute the command. So the given command is ls ../foo /bar and lets assume the value of PATH is ".:/sbin:/bin:/usr/bin". We would then try to first execute ./ls ../foo /bar then /usr/bin/ls ../foo /bar and at last /bin/ls ../foo /bar.

Hope this helps.

于 2012-09-29T10:37:02.980 回答
1

I think the issue is that you believe the shell is responsible for doing the work of ls. ls isn't really a "part" of the shell (in this case at least). The shell executes a program called ls. Most of the comments seem to be explaining how to find ls, but I don't believe that's what you're confused about.

You should consider carefully what the point of the shell is before you write it. The comments have indirectly pointed out the fact that the shell "simply" has to "call" programs like ls and chdir, not perform their tasks.

于 2012-09-29T10:39:31.167 回答
1

ls knows by itself that, if not given any arguments, it is supposed to list files in the current working directory as returned by getcwd

于 2012-09-29T10:52:53.257 回答