简体   繁体   English

外壳程序管道C

[英]Shell program pipes C

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: 我正在尝试运行一个小的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;
    }

I am having a problem when I compare cp and NULL, my program crashes. 比较cp和NULL时出现问题,程序崩溃。 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) 我想要的是在第二个集合或参数的输入完成后退出循环(这是我尝试使用if(strlen(cp)== NULL)进行的操作

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. Shell处理整个命令行,可以说,您的程序将仅获得命令行的共享。

Example: 例:

cat file1 file2 | sed s/frog/bat/

In the above example, cat is invoked with only two arguments, file1 , and file2 . 在上面的示例中,仅使用两个参数file1file2调用cat Also, sed is invoked with only a single argument: s/frog/bat/ . 同样,仅使用单个参数s/frog/bat/来调用sed

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() ; 由于strtok()刻划了原始command数组,因此您不必使用malloc()分配额外的空间; you could simply point the parameter[n] pointers to the relevant sections of the original command string. 您只需将parameter[n]指针指向原始命令字符串的相关部分即可。 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; 您分配了255个字符; 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. 您最多复制49个。最好等到将参数隔离之后再复制它-仅分配所需的空间。 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. 请注意,如果(指向该命令的路径)命令的字符数为50个或更多,则您将没有以null终止的字符串-由malloc()分配的空间不会为零,并且strncpy()不会在末尾写入零超长的弦。

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. 它是shell的一种表示法,而不是命令的参数列表的一部分。 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. 您还应确保第一个命令的参数列表以NULL指针终止,尤其是由于i刚好设置在MAX_ARG之下,因此您将不知道指定了多少个参数。

    {
        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. 设置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;
}

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. 在为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; }'

It doesn't much matter what it does (but it finds all checkins I made since 11th October on a particular branch in ClearCase); 它做什么并不重要(但是它将找到我自10月11日以来在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. (是的,可能应该进行优化-这样做是不值得的。)同样,这不一定是您现在需要处理的内容-但这确实使您知道需要去的地方。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM