简体   繁体   中英

ls | grep in shell written in C

I am trying to make my own shell in C. It uses one pipe and the input (for now) is static. I execute commands using execvp. Everything is fine except when I run the command ls |grep ".c" I get no results. Can anyone show me where is the problem and find a solution.

The shell so far:

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>

int   p[2];
int pid;
int r;

main()
{
    char *ls[] = {"ls", NULL};
    char *grep[] = {"grep", "\".c\"", NULL};

    pipe(p);

    pid = fork();
    if (pid  != 0) {
            // Parent: Output is to child via pipe[1]

            // Change stdout to pipe[1]
            dup2(p[1], 1);
            close(p[0]);

            r = execvp("ls", ls);
    } else {
            // Child: Input is from pipe[0] and output is via stdout.
            dup2(p[0], 0);
            close(p[1]);

            r = execvp("grep", grep);
            close(p[0]);
    }

    return r;
}

Remove the quotes in the argument to grep. ie, use

char *grep[] = {"grep", ".c", NULL};

If you are calling execvp , the usual shell expansion of arguments (ie, globbing, removal of quotes, etc) does not happen, so effectively what you are doing is the same as

ls | grep '".c"'

In a normal shell.

Also be aware that nothing that comes after the call to execvp will execute, execvp replaces the current process, it will never return.

You have multiple problems:

  1. One problem is that you have far too few calls to close() . When you use dup2() to replicate a file descriptor from a pipe to standard input or standard output, you should close both file descriptors returned by pipe() .

  2. A second problem is that the shell removes double quotes around arguments but you've added them around your. You are looking for files whose name contains ".c" (where the double quotes are part of the file name being searched for). Use:

     char *grep[] = { "grep", "\\\\.c$", NULL }; 

    This looks for a dot and a c at the end of the line.

  3. You should report failures after execvp() . If any of the exec*() functions returns, it failed. It can happen when the user mistypes a command name, for example. It is crucial that you report the error and that the child process then exits. If you don't do that, you can end up in a normal iterative shell (rather than this one-shot, non-iterative, non-interactive shell) with multiple shell processes all trying to read from the terminal at the same time, which leads to chaos and confusion.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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