Shell程序管道C

发布于 2024-12-11 10:46:40 字数 1429 浏览 0 评论 0原文

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

I am trying to run a small shell program and the first step to make sure my code is running properly is to make sure I get the correct command and parameters:

//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;
    }

I am having a problem when I compare cp and NULL, my program crashes. What I want is to exit the loop once the entries for the second set or parameters have finished (which is what I tried doing with the if(strlen(cp) == NULL)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

离笑几人歌 2024-12-18 10:46:40

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

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

示例:

cat file1 file2 | sed s/frog/bat/

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

I may have misunderstood the question, but your program won't ever see the pipe character, |.

The shell processes the entire command line, and your program will only be given it's share of the command line, so to speak.

Example:

cat file1 file2 | sed s/frog/bat/

In the above example, cat is invoked with only two arguments, file1, and file2. Also, sed is invoked with only a single argument: s/frog/bat/.

〗斷ホ乔殘χμё〖 2024-12-18 10:46:40

让我们看看您的代码:

parameter[0] = malloc(255);

由于 strtok() 分割了原始 command 数组,因此您不必使用 malloc() 分配额外的空间>;您只需将 parameter[n] 指针指向原始命令字符串的相关部分即可。但是,一旦您超越了以空格分隔的命令(在真正的 shell 中, | 符号不必被空格包围,但在您的 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);

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

    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

它做什么并不重要(但它会找到我自 10 月 11 日以来在 ClearCase 的特定分支上进行的所有签入);我使用的符号很重要。 (是的,它可能可以优化 - 不值得这样做。)同样,这不一定是您现在需要处理的 - 但它确实让您知道需要去哪里。

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

Let's look at your code:

parameter[0] = malloc(255);

Since strtok() carves up the original command array, you don't have to allocate extra space with malloc(); you could simply point the parameter[n] pointers to the relevant sections of the original command string. However, once you move beyond space-separated commands (in a real shell, the | symbol does not have to be surrounded by spaces, but it does in yours), then you will probably need to copy the parts of the command string around, so this is not completely wrong.

You should check for success of memory allocation.

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

You allocated 255 characters; you copy at most 49. It might be better to wait until you have the parameter isolated, and then duplicate it - allocating just the space that is needed. Note that if the (path leading to the) command name is 50 characters or more, you won't have a null-terminated string - the space allocated by malloc() is not zeroed and strncpy() does not write a trailing zero on an overlong string.

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

It is not clear that you should have an upper limit on the number of arguments that is as simple as this. There is an upper limit, but it is normally on the total length of all the arguments.

{
    parameter[i] = malloc(255);

Similar comments about memory allocation - and checking.

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

Oops! There goes the memory. Sorry about the leak.

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

I think it might be better to do this comparison before copying... Also, you don't want the pipe in the argument list of either command; it is a notation to the shell, not part of the command's argument lists. You should also ensure that the first command's argument list is terminated with a NULL pointer, especially since i is set just below to MAX_ARG so you won't know how many arguments were specified.

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

This feels odd; you isolate the command and then process its arguments separately. Setting i = MAX_ARG seems funny too since your next action is to break the loop.

        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;
}

You should probably only enter this loop if you found a pipe. Then this code leaks memory like the other one does (so you're consistent - and consistency is important; but so is correctness).

You need to review your code to ensure it handles 'no pipe symbol' properly, and 'pipe but no following command'. At some point, you should consider multi-stage pipelines (three, four, ... commands). Generalizing your code to handle that is possible.

When writing code for Bash or an equivalent shell, I frequently use notations such as this script, which I used a number of times today.

ct find /vobs/somevob \
    -branch 'brtype(dev.branch)' \
    -version 'created_since(2011-10-11T00:00-00:00)' \
    -print |
grep -v '/0

It doesn't much matter what it does (but it finds all checkins I made since 11th October on a particular branch in ClearCase); it's the notation that I was using that is important. (Yes, it could probably be optimized - it wasn't worth doing so.) Equally, this is not necessarily what you need to deal with now - but it does give you an inkling of where you need to go.

| 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; }'

It doesn't much matter what it does (but it finds all checkins I made since 11th October on a particular branch in ClearCase); it's the notation that I was using that is important. (Yes, it could probably be optimized - it wasn't worth doing so.) Equally, this is not necessarily what you need to deal with now - but it does give you an inkling of where you need to go.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文