【问题标题】:Writing a shell in C, doesn't return anything用C写一个shell,不返回任何东西
【发布时间】:2012-09-21 01:26:19
【问题描述】:

我运行我的 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]);


}

【问题讨论】:

  • 运行execv的返回值rv是多少?这可能会帮助您找出问题所在。
  • 您是否尝试过使用调试器? gdb 是一个很好的学习工具。

标签: c shell fork execv


【解决方案1】:

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

ISO C99 是这样定义字节的:

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

6.5.3.4 The sizeof operator 中的后续状态:

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

这在 C11 中没有改变。

所以,基本上,一个字节就是你的char 的大小。 ISO 通常将术语 octet 保留为 8 位值。


其次,语句序列如下:

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 是换行符。没有这样的可执行文件,因此来自execv 的错误 2 (ENOENT = No such file or directory) - 您需要修复解析代码,以便不留下换行符。

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

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>_

这只是一个调试证明,不适合真正的代码,所以你仍然必须去修复你的解析。


您可能想看看this answer,因为它显示了一种通过缓冲区溢出保护从用户那里获取输入的好方法,如果输入行太长,则清理其余的输入行,提示和(最重要的是case) 删除换行符。

【讨论】:

  • 公平地说,使用 sizeof(char) 可能是一种很好的编码习惯,以防其他人不知道你在做什么。我的意思是,那有什么开销:)
  • sizeof(char) 并不总是等于 1,那里有一些奇特的硬件,它们简单地不处理 1 字节字对齐,(超级计算机等),因此它们将使用 16 位或即使是 32 位字符,c 标准也允许这样做。此外,如果您决定将代码更改为使用 unichar,也可以使用 sizeof(char),那么您不太可能忘记更改 sizeof(char) == 1 假设。
  • @Nathan,没有符合 ISO 标准的 C 编译器,其中sizeof(char) != 1。 ISO 不将字节定义为 8 位(一个八位字节),而是定义为基本存储单元的大小,即一个字符。 1024 位字节是可能的,但这仍然是一个字节,并且每个字符有 一个 字节(字符将是 1024 位宽,即一个字节)。而且,如果您想处理对其他类型的扩展,则不要使用该类型(因为如果类型发生更改,您无论如何都必须更改它)。您使用变量:biggerchar *xyz = malloc (sizeof (*xyz));.
  • @NathanDay 你错了; C 标准要求 sizeof(char) == 1。
  • @user1397061 公平地说,使用 sizeof(char) 是不好的做法,因为它只是噪音,与现有的数百万行代码不一致,并且可能会误导幼稚的程序员思考这是需要的。
【解决方案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] 和 path(您要连接的字符串)的长度之和具有不可预测的关系。这可能会导致段错误。

【讨论】:

    【解决方案3】:

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

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

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

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

    希望这会有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-28
      • 2011-08-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多