【问题标题】:Shell program pipes CShell 程序管道 C
【发布时间】:2011-10-20 04:17:18
【问题描述】:

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

【问题讨论】:

标签: c shell unix pipe


【解决方案1】:

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

shell 处理整个命令行,可以这么说,您的程序只会获得命令行的份额。

例子:

cat file1 file2 | sed s/frog/bat/

在上面的示例中,cat 仅使用两个参数调用,file1file2。此外,sed 仅使用一个参数调用:s/frog/bat/

【讨论】:

  • 这完全取决于提问者所说的“小shell程序”是什么意思。
【解决方案2】:

让我们看看你的代码:

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 个或更多字符,则不会有以 null 结尾的字符串 - malloc() 分配的空间不会归零,strncpy() 不会在其上写入尾随零过长的字符串。

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

不清楚是否应该对这么简单的参数数量设置上限。有一个上限,但通常是所有参数的总长度。

{
    parameter[i] = malloc(255);

关于内存分配和检查的类似 cmets。

    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 的特定分支上所做的所有签入);我使用的符号很重要。 (是的,它可能会被优化——不值得这样做。)同样,这不一定是你现在需要处理的——但它确实让你知道你需要去哪里。

【讨论】:

  • 所以我稍微改了一下,但是当我比较 cp 和 NULL 时我的程序崩溃了,
猜你喜欢
  • 1970-01-01
  • 2016-06-03
  • 2011-12-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-25
相关资源
最近更新 更多