1

我运行我的shell,它提示:“ Shell>”。我输入一个命令,例如ls,它只是创建一个新行,Shell>再次显示“”。

知道为什么它似乎没有击中execv吗?

            int no_of_args = count(buffer);
            // plus one to make it NULL
            char** array_of_strings = malloc((sizeof(char*)*(no_of_args+1)));

            //  break the string up and create an array of pointers that
            // point to each of the arguments.
            int count=0;
            char* pch2;
            pch2 = strtok (buffer," ");
            while (pch2 != NULL)
            {
                array_of_strings[count]=(char*)malloc((sizeof(char)*strlen(pch2)));
                strcpy(array_of_strings[count], pch2);

                pch2 = strtok (NULL, " ");
                count++;
            }

            //format for command is eg. ls -a -l
            //therefore the first element in the array will be the program name
            //add the path so it'll be /bin/command eg. /bin/ls
            char* prog = malloc(sizeof(char)*(strlen(array_of_strings[0]+strlen(path))));
            prog = strcat(strcpy(prog, path),array_of_strings[0]);


}
4

3 回答 3

3

首先,你永远不需要使用它,sizeof(char)因为它总是 1。

ISO C99 如此定义字节:

数据存储的可寻址单元大到足以容纳执行环境的基本字符集的任何成员。

和后来的状态6.5.3.4 The sizeof operator

当应用于具有 char、unsigned char 或 signed char 类型(或其限定版本)的操作数时,结果为 1。

这在 C11 中没有变化。

所以,基本上,一个字节就是你的char. ISO 通常保留octet8 位值的术语。


其次,一个语句序列,如:

array_of_strings[count]=(char*)malloc((sizeof(char)*strlen(pch2)));
strcpy(array_of_strings[count], pch2);

是未定义的行为,因为strlen(pch2)只有足够空间来存储 . 指向的字符串的副本pch2。你应该使用类似的东西:

array_of_strings[count] = malloc (strlen (pch2) + 1);

您还会注意到我删除了演员表。您永远不应该在 C 中强制转换内存分配函数的返回值,因为它在某些情况下会隐藏问题。

第三,您似乎没有遵守argv阵列的规则。这个数组中的最后一个元素应该是一个 NULL 指针,因为在命令中ls x.txt会生成:

  • "ls".
  • "x.txt".
  • NULL.

现在,针对您的具体问题。您应该检查execv调用的返回值,因为不能保证可执行文件会运行(例如,如果ls不在/bin目录中)。我会改变:

int rv = execv(prog, array_of_strings);

进入:

printf ("DEBUG: [%s]\n", prog);
int rv = execv(prog, array_of_strings);
printf ("DEBUG: execv returned %d/%d\n", rv, errno); // need errno.h

出于调试目的,并查看输出的内容。

如果execv有效,您将永远不会看到最后的消息。如果它出现,它会告诉你为什么execv没有工作。当我这样做时,我看到:

DEBUG: [/bin/ls
]
DEBUG: execv returned -1/2

换句话说,您尝试运行的可执行文件名称是/bin/lsX,其中X是换行符。没有这样的可执行文件,因此错误 2 ( ENOENT = No such file or directory) 来自execv- 您需要修复解析代码,以便不留下换行符。

作为快速调试修复,我更改了以下行:

prog = strcat(strcpy(prog, path),array_of_strings[0]);

进入:

prog = strcat(strcpy(prog, path),array_of_strings[0]);
if (prog[strlen(prog)-1] == '\n') prog[strlen(prog)-1] = '\0';

摆脱尾随换行符,如果它在那里,那么文件列表就成功了:

Shell>ls
DEBUG: [/bin/ls]
accounts2011.ods  birthdays    shares    workspace_android
accounts2012.ods  development  wildlife
Shell>_

那只是为了证明而调试的东西,不适合真正的代码,所以你仍然必须去修复你的解析。


您可能想看看这个答案,因为它显示了一种通过缓冲区溢出保护从用户那里获取输入的好方法,如果太长,清理输入行的其余部分,提示并(在这种情况下最重要)删除换行符。

于 2012-09-21T01:43:15.690 回答
2

线

char* prog = malloc(sizeof(char)*(strlen(array_of_strings[0]+strlen(path))));

似乎错了。你确定你不是这个意思

char* prog = malloc(sizeof(char)*(strlen(array_of_strings[0])+strlen(path)));

(注意移动括号)。(您要保留的字节数)将与路径(您尝试连接的字符串)strlen(array_of_strings[0]+strlen(path))的长度之和具有不可预测的关系。array_of_strings[0]这可能会导致段错误。

于 2012-09-21T02:01:08.527 回答
0

execv 之后的当前工作目录也发生了一些奇怪的事情。尝试“Shell>pwd”,甚至“Shell>ls /home/”。

无论如何,我想我可能已经通过在 fgets 之后删除“缓冲区”字符串末尾的 '\n' 字符来解决它。看看它是否适合你:

 fgets(buffer, 512, stdin);
 int j = strlen(buffer) - 1;
 if (buffer[j] == '\n')
     buffer[j] = 0;

为什么会发生奇怪的 CWD 行为对我来说仍然是个谜……

希望这可以帮助。

于 2012-09-21T02:16:24.560 回答