重定向后没有这样的文件或目录 - 简单的命令行程序

时间:2017-08-07 00:47:40

标签: c linux redirect command-line

我编写一个shell。这是处理重定向的一小部分。我只包含导致错误的代码段。程序的这一部分应该采用命令/参数行并相应地执行该行。 wc<垃圾> junk2是一个命令行输入的例子,由于某种原因,当我执行该行时,它产生了错误垃圾:>:open:没有这样的文件或目录。程序的其余部分运行良好,但它在这里打破。

:wc<垃圾> junk2

junk: >: open: No such file or directory

   1       4      31 junk2
   1       4      31 total

我简单地说它按预期工作但由于某种原因我必须丢失一块拼图,因为它再次被打破了。

我看过我的数组值,它们和预期的一样。为了澄清一点,我使用了arguments数组的副本,因此通过将参数copy值设置为NULL来保持原始值不变。我将参数复制值设置为null,因此循环不会重复使用重定向。

如果您有任何建议或看到我显然无法解决的问题,我们将不胜感激。

    while (arguments[i] != NULL)
                        {


                            if ((strcmp(argumentsCopy[i], "<") == 0))
                            {
                                if ((access(argumentsCopy[i + 1], R_OK) == -1))
                                {
                                    printf("Cannot open %s for input\n", argumentsCopy[i + 1]);
                                    fflush(stdout);
                                    redirect = 1;
                                }
                                else
                                {

                                    int fd = open(argumentsCopy[i + 1], O_RDONLY);
                                    dup2(fd, STDIN_FILENO);
                                    close(fd);
                                    argumentsCopy[i] = NULL;
                                    redirect = 1;
                                    execvp(command, &arguments[i + 1]);
                                }

                            }
                            if ((strcmp(argumentsCopy[i], ">") == 0))
                            {


                                int fd = open(argumentsCopy[ i + 1], O_RDWR);
                                dup2(fd, STDOUT_FILENO);
                                close(fd);
                                argumentsCopy[i] = NULL;
                                redirect = 1;  // avoid repeat use of redirection symbol in arguments array
                                execvp(command, &arguments[i + 1]);
                            }

                            i++;
                        }
                        if (redirect == 0)
                        {

                            execvp(command, execArgs);  //execArgs is entire command w/ arguments
                        }
                        exit 0; //default if error occurred. 

1 个答案:

答案 0 :(得分:1)

首先,请注意您未正确使用execvp功能。一旦对execvp(或exec系列中的任何调用)的调用成功,当前程序的执行将终止,并由您exec的程序替换。因此,除非该呼叫失败,否则控制流不应该经过execvp呼叫。因此,在确定execvpstdin文件描述符都已正确重定向(如果您同时具有输入和输出重定向)之前,无法调用stdout。从您的代码示例中,一旦检测到任何一个,您就会调用execvp,这意味着您的shell只能重定向输入输出,而不是两者。

但是,这不是您收到的错误的来源。考虑输入wc < junk > junk2。根据您提供的信息,命令和参数数组将按如下方式填充:

command = "wc"
arguments[0] = ">"
arguments[1] = "junk"
arguments[2] = "<"
arguments[3] = "junk2"
arguments[4] = NULL

i = 0时,将采用第一个if语句,打开文件描述符并使用参数execvpcommand执行&arguments[i+1]。这些对应于要执行的文件和分别传递给该函数的main方法的argv数组。在这种情况下,命令为wc,args为{ "junk", "<", "junk2", NULL }(因为这是从&arguments[i+1]开始的空终止数组的值)。在Unix系统上,第一个参数(argv[0])通常是当前程序的名称。因此,实际的命令行参数从argv[1]开始(有关文档,请参阅Program Arguments)。从wc的角度来看,它应该处理的命令行参数是{ "<", "junk2", NULL },它处理了它认为的程序名称argv[0]junk

wc将其处理的文件列表作为参数。在这种情况下,它认为列表为<junk2,因为"<"是由bash和其他shell识别的运算符,而不是正在执行的程序。因此,wc(由于junk认为其名称为argv[0])尝试将<作为输入文件打开并失败,请打印消息:

junk: >: open: No such file or directory