Shell程序管道C.

时间:2011-10-20 04:17:19

标签: c shell unix pipe

我正在尝试运行一个小型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)

2 个答案:

答案 0 :(得分:1)

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

shell处理整个命令行,你的程序只会得到它在命令行中的份额,可以这么说。

示例:

cat file1 file2 | sed s/frog/bat/

在上面的示例中,仅使用两个参数catfile1调用file2。此外,仅使用一个参数调用seds/frog/bat/

答案 1 :(得分:0)

让我们来看看你的代码:

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指针终止,特别是因为i设置在MAX_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的一个特定分支上制作的所有签到);这是我使用的符号很重要。 (是的,它可能会被优化 - 这不值得这样做。)同样,这不一定是你现在需要处理的 - 但它确实能让你了解你需要去的地方。