Shell程序pipe道C

我想运行一个小的shell程序,并确保我的代码正常运行的第一步是确保我得到正确的命令和参数:

//Split the command and store each string in parameter[] cp = (strtok(command, hash)); //Get the initial string (the command) parameter[0] = (char*) malloc(strlen(cp)+ 1); //Allocate some space to the first element in the array strncpy(parameter[0], cp, strlen(cp)+ 1); for(i = 1; i < MAX_ARG; i++) { cp = strtok(NULL, hash); //Check for each string in the array parameter[i] = (char*) malloc(strlen(cp)+ 1); strncpy(parameter[i], cp, strlen(cp)+ 1); //Store the result string in an indexed off array if(parameter[i] == NULL) { break; } if(strcmp(parameter[i], "|") == 0) { cp = strtok(NULL, hash); parameter2[0] = (char*) malloc(strlen(cp)+ 1); strncpy(parameter2[0], cp, strlen(cp)+ 1); //Find the second set of commands and parameters for (j = 1; j < MAX_ARG; j++) { cp = strtok(NULL, hash); if (strlen(cp) == NULL) { break; } parameter2[j] = (char*) malloc(strlen(cp)+ 1); strncpy(parameter2[j], cp, strlen(cp)+ 1); } break; } 

我有一个问题,当我比较CP和NULL,我的程序崩溃。 我想要的是一旦第二组或参数的条目已经完成(这是我试图用if(strlen(cp)== NULL)来退出循环)

我可能误解了这个问题,但是你的程序不会看到管道字符|

shell处理整个命令行,你的程序只会被分配给命令行,可以这么说。

例:

 cat file1 file2 | sed s/frog/bat/ 

在上面的例子中,只用两个参数file1file2来调用cat 。 另外, sed只用一个参数调用: s/frog/bat/

让我们看看你的代码:

 parameter[0] = malloc(255); 

由于strtok()分割了原始的command数组,所以你不必为malloc()分配额外的空间。 您可以简单地将parameter[n]指针指向原始命令字符串的相关部分。 但是,一旦超出空格分隔的命令(在真实的shell中, |符号不必被空格包围,而是在你的空格中),则可能需要复制命令字符串的各个部分,所以这不是完全错误的。

你应该检查内存分配的成功。

 cp = strtok(command, " "); //Get the initial string (the command) strncpy(parameter[0], cp, 50); 

你分配了255个字符; 您最多可复制49个。最好等到您将参数隔离后再复制 – 只分配所需的空间。 请注意,如果(指向该路径的)命令名称的长度是50个或更多,则不会有空终止的字符串 – 由malloc()分配的空间不会归零,并且strncpy()不会写入尾随零一个过长的字符串。

 for (i = 1; i < MAX_ARG; i++) 

不清楚你应该有一个这样简单的参数数量的上限。 有一个上限,但它通常是所有参数的总长度。

 { parameter[i] = malloc(255); 

关于内存分配的类似评论 – 和检查。

  cp = strtok(NULL, " "); parameter[i] = cp; 

哎呀! 有记忆。 对于泄漏抱歉。

  if (strcmp(parameter[i], "|") == 0) 

我认为在复制之前做这个比较可能会更好…另外,你不需要在任何一个命令的参数列表中使用管道; 它是shell的标记,不是命令参数列表的一部分。 你还应该确保第一个命令的参数列表是以NULL指针终止的,特别是因为iMAX_ARG下面设置,所以你不知道指定了多少个参数。

  { i = MAX_ARG; cp = strtok(NULL, " "); parameter2[0] = malloc(255); strncpy(parameter2[0], cp, 50); 

这感觉很奇怪, 您隔离该命令,然后分别处理其参数。 设置i = MAX_ARG似乎也很有趣,因为你的下一个行动是打破循环。

  break; } if(parameter[i] == NULL) { break; } } //Find the second set of commands and parameter //strncpy(parameter2[0], cp, 50); for (j = 1; j < MAX_ARG; j++) { parameter2[j] = malloc(255); cp = strtok(NULL, " "); parameter2[j] = cp; } 

如果你找到一个管道,你应该只能进入这个循环。 然后这个代码像另一个一样泄漏内存(所以你是一致的 – 一致性是重要的,但是正确性也是如此)。

您需要检查您的代码以确保它正确处理“无管道符号”,并且“管道但没有以下命令”。 在某个时候,你应该考虑多级流水线(三,四,…命令)。 推广你的代码来处理这是可能的。

当为Bash或者等价的shell编写代码的时候,我经常使用诸如这个脚本的符号,这个脚本我今天使用了很多次。

 ct find /vobs/somevob \ -branch 'brtype(dev.branch)' \ -version 'created_since(2011-10-11T00:00-00:00)' \ -print | grep -v '/0$' | xargs ct des -fmt '%u %d %Vn %En\n' | grep '^jleffler ' | sort -k 4 | awk '{ printf "%-8s %s %-25s %s\n", $1, $2, $3, $4; }' 

它没有太大关系(但是它找到了我自10月11日以来在ClearCase的一个特定分支上所做的所有检查)。 这是我使用的符号很重要。 (是的,它可能会被优化 – 这是不值得这样做的。)同样,这不一定是你现在需要处理的 – 但它确实给你一个你需要去的地方。