anorthosi
anorthosi

Reputation: 31

Why doesn't execlp allow me to use a pipe?

#include <stdio.h>
#include <unistd.h>
main()
{
    execlp("ls" , "ls", "-l", "|" , "sort", NULL);    
}

What's going wrong? Please help.

If I write this: execlp("ls" , "ls", "-l", NULL); then the result displays on screen and if I try this execlp("ls" , "ls", "-l", "|" , "sort", NULL); screen displays error message cannot access.

Why? Does anyone have any idea? Why doesn't it allow me to use pipe (|) when I execute the command execlp?

Upvotes: 1

Views: 3271

Answers (4)

Bruno Parmentier
Bruno Parmentier

Reputation: 1239

When you write the following command in a shell

ls -l | sort

two programs are executed: ls and sort.

The pipe character (|) means that the output of the first should be redirected to the standard input of the second. This pipe is interpreted by your shell. It is not a parameter of your command.

execlp takes the name of your program and its parameters as arguments.

So when you write

execlp("ls" , "ls", "-l", "|" , "sort", NULL);

it doesn't make any sense since | and sort are not parameters of ls.

What you want is do what the shell does for you:

  1. declare a pipe
  2. make a fork where you redirect stdout to your pipe (with dup) and execute ls:

    execlp("ls" , "ls", "-l", NULL);
    
  3. make a fork where you redirect your pipe to stdin and execute sort:

    execlp("sort" , "sort", NULL);
    
  4. close your pipe, wait, etc.

Upvotes: 2

ZbyszekKr
ZbyszekKr

Reputation: 512

There is a simple way of doing this. It involves using function popen:

#include <stdio.h>
#include <unistd.h>

int main() {

    FILE* out  = popen("ls -l | sort", "w");

    pclose(out);

    return 0;  
}

However it might be not what you were going for as it doesn't use exec.

Upvotes: 1

Serge Ballesta
Serge Ballesta

Reputation: 148890

Oups, you a making a confusion. exec... family functions allow execution of one single program replacing the caller one. So your program just execute ls command with "-l", "|" , "sort" as parameters.

Here is what it gives interactively :

$ ls "-l" "|" "sort"
ls: sort: No such file or directory
ls: |: No such file or directory

On the other end, then you execute normaly ls -l | sort in a shell, the | is interpreted by the shell. And the shell :

  • starts ls -l as a first command
  • starts sort as a second command
  • with output of first command connected to input of second.

You can do that explicitely with the help of fork, pipe and execlp, but you will have to prepare the pipe, and explicitely fork in order to have 2 processes.

Alternatively, you can ask the shell to do the job :

execlp("/bin/sh" , "sh", "-c", "ls -l | sort", NULL);

Upvotes: 2

John Kugelman
John Kugelman

Reputation: 361585

Piping is a shell construct. execlp() isn't subject to shell parsing; it passes the arguments directly to the named command. To get shell features you need to explicitly start a shell process.

execl("/bin/sh", "/bin/sh", "-c", "ls -l | sort", NULL);

In that case it's probably best to specify the absolute path to the shell /bin/sh, which means you can use execl instead of execlp.

Upvotes: 2

Related Questions