我正在构建一个Linux Shell,我目前头痛的是将命令行参数传递给forked / exec'ed程序和系统函数。
目前,所有输入都在空格和新行上以全局变量char * parsed_arguments进行标记化。例如,输入 dir / usa / folderb 将被标记为:
parsed_arguments[0] = dir
parsed_arguments[1] = /usa/folderb
parsed_arguments将所有内容完美地标记;我现在的问题是我希望只获取parsed_arguments的一个子集,它排除了在shell中运行的可执行文件的命令/第一个参数/路径,并将它们存储在一个名为passed_arguments的新数组中。
所以在上一个例子中 dir / usa / folderb
parsed_arguments[0] = dir
parsed_arguments[1] = /usa/folderb
passed_arguments[0] = /usa/folderb
passed_arguments[1] = etc....
目前我没有任何运气,所以我希望有人可以帮助我。以下是我目前工作的一些代码:
我是如何复制参数的:
void command_Line()
{
int i = 1;
for(i;parsed_arguments[i]!=NULL;i++)
printf("%s",parsed_arguments[i]);
}
读取命令的功能:
void readCommand(char newcommand[]){
printf("readCommand: %s\n", newcommand);
//parsed_arguments = (char* malloc(MAX_ARGS));
// strcpy(newcommand,inputstring);
parsed = parsed_arguments;
*parsed++ = strtok(newcommand,SEPARATORS); // tokenize input
while ((*parsed++ = strtok(NULL,SEPARATORS)))
//printf("test1\n"); // last entry will be NULL
//passed_arguments=parsed_arguments[1];
if(parsed[0]){
char *initial_command =parsed[0];
parsed= parsed_arguments;
while (*parsed) fprintf(stdout,"%s\n ",*parsed++);
// free (parsed);
// free(parsed_arguments);
}//end of if
command_Line();
}//end of ReadCommand
分叉功能:
else if(strstr(parsed_arguments[0],"./")!=NULL)
{
int pid;
switch(pid=fork()){
case -1:
printf("Fork error, aborting\n");
abort();
case 0:
execv(parsed_arguments[0],passed_arguments);
}
}
这是我的shell目前输出的内容。我第一次运行它时会输出接近我想要的东西,但是每次后续调用都会破坏程序。此外,每个附加调用都会将解析后的参数附加到输出中。
这是原始shell产生的。它再次接近我想要的,但并不完全。我想省略命令(即“./testline”)。
答案 0 :(得分:1)
您的testline
程序在您的工具箱中是明智的;我有一个类似的程序,我称之为al
(对于Argument List)打印其参数,每行一个。它不会打印argv[0]
(我知道它被称为al
)。您也可以轻松安排testline
跳过argv[0]
。请注意,Unix惯例是argv[0]
是程序的名称;你不应该试图改变它(你将与整个系统作斗争)。
#include <stdio.h>
int main(int argc, char **argv)
{
while (*++argv != 0)
puts(*argv);
return 0;
}
你的函数command_line()
也是合理的,除了它不必要地依赖于全局变量。将全局变量视为难闻的气味(例如,H 2 S);尽可能避免它们。它应该更像是:
void command_Line(char *argv[])
{
for (int i = 1; argv[i] != NULL; i++)
printf("<<%s>>\n", argv[i]);
}
如果您遇到C89,则需要在循环外声明int i;
并在循环控件中仅使用for (i = 1; ...)
。请注意,此处的打印会单独分隔一行上的每个参数,并将其用标记字符(<<
和>>
- 将其括起来 - 以适应您的想法和偏见)。可以跳过循环中的换行符(可能使用空格代替),然后在循环后添加换行符(putchar('\n');
)。这使得更好,更接近通用的调试例程。 (当我编写'转储'函数时,我通常使用void dump_argv(FILE *fp, const char *tag, char *argv[])
以便我可以打印到标准错误或标准输出,并包含一个标记字符串来标识转储的写入位置。)
不幸的是,鉴于readCommand()
函数的碎片性质,不可能对它进行连贯的批判。注释掉的行足以引起关注,但如果没有您运行的实际代码,我们无法猜出您正在制作什么样的问题或错误。如图所示,它相当于:
void readCommand(char newcommand[])
{
printf("readCommand: %s\n", newcommand);
parsed = parsed_arguments;
*parsed++ = strtok(newcommand, SEPARATORS);
while ((*parsed++ = strtok(NULL, SEPARATORS)) != 0)
{
if (parsed[0])
{
char *initial_command = parsed[0];
parsed = parsed_arguments;
while (*parsed)
fprintf(stdout, "%s\n ", *parsed++);
}
}
command_Line();
}
变量parsed
和parsed_arguments
都是全局变量,变量initial_command
已设置但未使用(又名“无意义”)。 if (parsed[0])
测试不安全;你增加了前一行中的指针,因此它指向不确定的内存。
表面上看,从屏幕截图来看,你没有在第二次使用时正确地重置parsed_arguments[]
和/或passed_arguments[]
数组;它可能是一个未设置为零的索引。在不知道如何分配数据的情况下,很难知道你可能做错了什么。
我建议关闭此问题,返回您的系统并生成最小的SSCCE。它应该在大约100行以下;它不需要执行execv()
(或fork()
),但应使用上面command_Line()
函数的变体打印要执行的命令。如果此答案阻止您删除(关闭)此问题,请使用您的SSCCE代码对其进行编辑,并通过对此答案的评论通知我,以便我看到您已完成此操作。