In my program I'm executing given command and getting result (log, and exit status). Also my program have to support shell specific commands (i.e. commands which contains shell specific characters ~(tild),|(pipe),*). But when I try to run sh -c ls | wc
in my home directory via my program it failed and its exit status was 32512, also in stderr stream "sh: ls | wc: command not found"
was printed.
But the interesting thing is that the command sh -c ls | wc
works correct if I run it in shell.
What is the problem? Or more preferable how can I run shell specific commands via my program (i.ec which command with which parameters should I run)?
The code part bellow is in child part after fork(). It executs the command.
tokenized_command
is std::vector<std::string>
where in my case "sh", "-c", "ls", "|", "wc"
are stored, also I have tried to store there "sh", "-c", "\"ls | wc\""
but result is same. command
is char *
where full command line is stored.
boost::shared_array<const char *> bargv(new const char *[tokenized_command.size() + 1]);
const char **argv = bargv.get();
for(int i = 0; i < tokenized_command.size(); ++i)
{
argv[i] = tokenized_command[i].c_str();
printf("argv[%d]: %s\n", i, argv[i]); //trace
}
argv[tokenized_command.size()] = NULL;
if(execvp(argv[0], (char * const *)argv) == -1)
{
fprintf(stderr, "Failed to execute command %s: %s", command, strerror(errno));
_exit(EXIT_FAILURE);
}
P.S.
I know that using system(command)
instead execvp
can solve my problem. But system()
waits until command is finished, and this is not good enough for my program. And also I'm sure that in implementation of system()
one of exec-family functions is used, so the problem can be solved via exec
as well, but I don't know how.
You should execute
sh -c 'ls | wc'
.Option
-c
expects a command in form of string. In shell of course it is working, because there is no difference between spawningls
and redirecting output towc
and launchingls | wc
in separate shell.execvp
takes a path to an executable, and arguments with which to launch that executable. It doesn't take bourne shell commands.ls | wc
is a bourne shell command (among others), and it can't be broken down into the path to an executable and some arguments due to the use of a pipe. This means it can't be executed usingexecvp
.To execute a bourne shell command using
execvp
, one has to executesh
and pass-c
and the command for arguments.So you want to execute
ls | wc
usingexecvp
.You apparently tried
That would be the same as bourne shell command
sh -c ls '|' wc
.And both are very different than shell command
sh -c ls | wc
. That would beYou seem to think
|
andwc
are passed to thesh
, but that's not the case at all.|
is a special character which results in a pipe, not an argument.As for the exit code,
32512 = 0x7F00
So it didn't die from a signal, a core dump wasn't produced, and it exited with code 127 (0x7F).
What 127 means is unclear, which is why it should accompanied by an error message. You tried to execute program
ls | wc
, but there is no such program.