用C编写shell,不需要';我什么也不退
我运行shell,它会提示:“用C编写shell,不需要';我什么也不退,c,shell,fork,execv,C,Shell,Fork,Execv,我运行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)));
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]);
}
首先,您永远不需要使用sizeof(char)
,因为它总是1
ISO C99对字节的定义如下:
可寻址的数据存储单元,大到足以容纳基本字符的任何成员
执行环境的集合
随后在6.5.3.4中说明了运算符的大小:
应用于具有char、unsigned char或signed char类型的操作数时,
(或其合格版本)结果为1
这在C11中是不变的
因此,基本上,一个字节就是char
的大小。ISO通常将术语“八位字节”保留为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
数组的规则。此数组中的最后一个元素应为空指针,因为在命令ls x.txt
中将生成:
“ls”
“x.txt”
NULL
现在,谈谈你的具体问题。您应该检查execv
调用的返回值,因为无法保证可执行文件将运行(例如,如果ls
不在/bin
目录中)。我会改变:
int rv = execv(prog, array_of_strings);
进入:
用于调试目的,并查看其输出
如果execv
有效,您将永远看不到最后一条消息。如果出现,它将告诉您为什么execv
无法工作。当我这样做时,我看到:
DEBUG: [/bin/ls
]
DEBUG: execv returned -1/2
换句话说,您试图运行的可执行文件名是/bin/lsX
,其中X
是换行符。没有这样的可执行文件,因此出现了execv
中的错误2(enoint=no-this-file或directory
)-您需要修复解析代码,以便新行不会保留在中
作为快速调试修复,我更改了以下行:
prog = strcat(strcpy(prog, path),array_of_strings[0]);
进入:
要删除尾随的换行符(如果有),并成功列出文件,请执行以下操作:
Shell>ls
DEBUG: [/bin/ls]
accounts2011.ods birthdays shares workspace_android
accounts2012.ods development wildlife
Shell>_
这只是一个用于验证的调试工作,不适用于实际代码,所以您仍然必须去修复您的解析
您可能想看一看,因为它显示了一种使用缓冲区溢出保护从用户处获取输入的好方法,如果输入行太长,则清除其余的输入行,并提示和(在本例中最重要的)删除换行符。首先,您永远不需要使用sizeof(char)
,因为它总是1
ISO C99对字节的定义如下:
可寻址的数据存储单元,大到足以容纳基本字符的任何成员
执行环境的集合
随后在6.5.3.4中说明了运算符的大小:
应用于具有char、unsigned char或signed char类型的操作数时,
(或其合格版本)结果为1
这在C11中是不变的
因此,基本上,一个字节就是char
的大小。ISO通常将术语“八位字节”保留为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
数组的规则。此数组中的最后一个元素应为空指针,因为在命令ls x.txt
中将生成:
“ls”
“x.txt”
NULL
现在,谈谈你的具体问题。您应该检查execv
调用的返回值,因为无法保证可执行文件将运行(例如,如果ls
不在/bin
目录中)。我会改变:
int rv = execv(prog, array_of_strings);
进入:
用于调试目的,并查看其输出
如果execv
有效,您将永远看不到最后一条消息。如果出现,它将告诉您为什么execv
无法工作。当我这样做时,我看到:
DEBUG: [/bin/ls
]
DEBUG: execv returned -1/2
换句话说,您试图运行的可执行文件名是/bin/lsX
,其中X
是换行符。没有这样的可执行文件,因此出现了execv
中的错误2(enoint=no-this-file或directory
)-您需要修复解析代码,以便新行不会保留在中
作为快速调试修复,我更改了以下行:
prog = strcat(strcpy(prog, path),array_of_strings[0]);
进入:
要删除尾随的换行符(如果有),并成功列出文件,请执行以下操作:
Shell>ls
DEBUG: [/bin/ls]
accounts2011.ods birthdays shares workspace_android
accounts2012.ods development wildlife
Shell>_
这只是一个用于验证的调试工作,不适用于实际代码,所以您仍然必须去修复您的解析
您可能想看一看,因为它显示了一种使用缓冲区溢出保护从用户处获取输入的好方法,如果输入行太长,请清理输入行的其余部分,并提示(在本例中最重要的)删除换行符。换行符
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(字符串数组[0]+strlen(路径))
(保留的字节数)将承载不可预测的