简体   繁体   English

用C编写Shell,不返回任何内容

[英]Writing a shell in C, doesn't return anything

I run my shell and it prompts: " Shell> ". 我运行外壳程序,并提示:“ Shell> ”。 I type a command, like ls , and it just makes a new line that says " Shell> " again. 我输入一个命令,如ls ,它只是在新行中再次显示“ Shell> ”。

Any idea why it doesn't seem to be hitting execv ? 知道为什么它似乎没有达到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]);


}

First things first, you never need to use sizeof(char) since it's always 1. 首先,您永远不需要使用sizeof(char)因为它始终为1。

ISO C99 defines byte thus: ISO C99定义字节因此:

addressable unit of data storage large enough to hold any member of the basic character set of the execution environment. 数据存储的可寻址单元,其大小足以容纳执行环境的基本字符集的任何成员。

and later states in 6.5.3.4 The sizeof operator : 及更高版本在6.5.3.4 The sizeof operator声明:

When applied to an operand that has type char, unsigned char, or signed char, (or a qualified version thereof) the result is 1. 当将其应用于具有char,unsigned char或signed char类型(或其限定版本)的操作数时,结果为1。

This is unchanged in C11. 在C11中不变。

So, basically, a byte is the size of your char . 因此,基本上,一个字节就是char的大小。 ISO generally reserves the term octet for an 8-bit value. ISO通常为8位值保留术语octet


Secondly, a statement sequence like: 其次,一条语句序列如下:

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

is undefined behaviour since strlen(pch2) is just one short of being enough space to store a copy of the string pointed to by pch2 . 是因为未定义行为strlen(pch2)是一种存在足够的空间来存储字符串的副本通过指向只有一个 pch2 You should be using something like: 您应该使用类似:

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

You'll also notice I removed the cast. 您还会注意到我删除了演员表。 You should never cast the return value of memory allocation functions in C since it can hide problems under some circumstances. 切勿在C中强制转换内存分配函数的返回值,因为它在某些情况下会隐藏问题。

Thirdly, you don't seem to be following the rules with your argv array. 第三,您似乎并没有遵循argv数组的规则。 The last element in this array should be a NULL pointer, as in the command ls x.txt would generate: 该数组中的最后一个元素应为NULL指针,如ls x.txt命令将生成:

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

Now, on to your specific problem. 现在,解决您的特定问题。 You should be checking the return value from your execv call since there's no guarantee that the executable will run (for example, if ls were not in the /bin directory). 您应该检查execv调用的返回值,因为不能保证可执行文件会运行(例如,如果ls不在/bin目录中)。 I would change: 我会改变:

int rv = execv(prog, array_of_strings);

into: 变成:

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

for debugging purposes, and see what that outputs. 用于调试目的,并查看输出结果。

If the execv works, you'll never see that final message. 如果execv有效,您将永远看不到最后一条消息。 If it appears, it will tell you why the execv didn't work. 如果出现,它将告诉您execv无法正常工作的原因。 When I do that, I see: 当我这样做时,我看到:

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

In other words, the executable name that you're trying to run is /bin/lsX , where X is the newline character. 换句话说,您要运行的可执行文件名称是/bin/lsX ,其中X是换行符。 There's no such executable, hence the error 2 ( ENOENT = No such file or directory ) from execv - you need to fix up the parsing code so that the newline is not left in. 没有这样的可执行文件,因此execv的错误2( ENOENT = No such file or directory )-您需要修复解析代码,以免遗漏换行符。

As a quick debug fix, I changed the line: 作为快速调试修复,我更改了这一行:

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

into: 变成:

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

to get rid of the trailing newline if it's there, and the file listing was then successful: 删除尾随的换行符(如果有的话),然后文件列表成功:

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

That's just a debugging thing for proof, unsuitable for real code, so you still have to go and fix your parsing. 那只是为了证明的调试工作,不适合实际代码,因此您仍然必须去修复解析。


You might want to have a look at this answer as it shows a good way to get input from the user with buffer overflow protection, cleaning up the rest of the input line if too long, prompting and (most important in this case) removal of the newline. 您可能想看看这个答案,因为它显示了一种通过缓冲区溢出保护从用户获取输入的好方法,如果输入的时间过长,则清理其余的输入行,提示并(在这种情况下最重要的)删除换行符。

The line 线

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

seems wrong. 似乎错了。 Are you sure you don't mean 你确定你不是故意的

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

(note moved parenthesis). (请注意移动括号)。 strlen(array_of_strings[0]+strlen(path)) (the number of bytes you're reserving) will bear an unpredictable relationship to the sum of the lengths of array_of_strings[0] and path (the strings you're trying to concatenate). strlen(array_of_strings[0]+strlen(path)) (您保留的字节数)与array_of_strings[0]的长度和path(您要连接的字符串)的总和具有不可预测的关系。 This may be causing a segfault. 这可能导致段错误。

There is also something weird happening with the current working directory after the execv. execv之后,当前工作目录也发生了一些奇怪的事情。 Try "Shell>pwd", or even "Shell>ls /home/". 尝试“ Shell> pwd”,甚至“ Shell> ls / home /”。

Anyway, I think I might have solved it by removing the '\\n' character at the end of the "buffer" string, right after the fgets. 无论如何,我认为我可以通过在fget之后紧接着删除“ buffer”字符串末尾的'\\ n'字符来解决此问题。 See if it works for you: 看看是否适合您:

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

Still a mystery to me why the weird CWD behaviour happened... 对于我为什么还发生奇怪的CWD行为,我仍然是个谜。

Hope this helps. 希望这可以帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM