Reputation: 71
My execvp
is not running ls -l *.c
command. I have tried to use two methods :
\bin\ls
.#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
char *cmdargs[] = { "ls", "-l", "*.c", NULL };
pid_t pid;
pid = fork();
if (pid == 0)
execvp("\bin\ls", cmdargs);
else
{
wait(NULL);
printf("Child terminates\n");
}
return 0;
}
Output :
ls: *.c: No such file or directory
Child terminates
cmdargs[0]
instead of the file path.#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
char *cmdargs[] = { "ls", "-l", "*.c", NULL };
pid_t pid;
pid = fork();
if (pid == 0)
execvp(cmdargs[0], cmdargs);
else
{
wait(NULL);
printf("Child terminates\n");
}
return 0;
}
Output:
ls: *.c: No such file or directory
Child terminates
When I just run the command ls -l *.c
, it does show me all the files which end with .c
. Execvp does not show me the files. There was a question related to this but that did not help me.
Upvotes: 0
Views: 545
Reputation: 370357
When you enter ls -l *.c
, the shell will parse that command, find the glob pattern and expand it. It will then call ls
with the expanded argument list, calling execvp
with an array like {"ls", "-l", "a.c", "b.c", "c.c", NULL}
. Neither ls
nor the execvp
expand globs by themselves, it's the shell that does it.
So if you want to use globs, your options are to either expand them yourself (either by manually going through the current directory and adding all files that end with .c
to your array or by using the POSIX glob function), or to go through the shell. You can do the latter either by explicitly invoking by using {"sh", "-c", "ls -l *.c", NULL}
as the array you pass to execvp
(or similarly, but without the array, using execl
etc.) or you could use system("ls -l *.c")
, which always goes through the shell.
Note that you definitely don't want to go through the shell if the arguments contain untrusted user input, so in that case expanding the glob(s) yourself / using glob
would be the way to go.
Upvotes: 0
Reputation: 141463
Alternatively to invoking the shell to expand the *.c
glob pattern to files, you can use glob to expand *.c
to list of files yourself and then construct a dynamically allocated array of arguments.
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <glob.h>
#include <stdlib.h>
int main() {
glob_t result = {0};
int err = glob("*.c", GLOB_ERR, NULL, &result);
if (err) return err;
char **cmdargs = malloc((2 + result.gl_pathc + 1) * sizeof(cmdargs));
if (cmdargs == NULL) return EXIT_FAILURE;
cmdargs[0] = "ls";
cmdargs[1] = "-l";
for (size_t i = 0; i < result.gl_pathc; ++i) {
cmdargs[i + 2] = result.gl_pathv[i];
}
cmdargs[2 + result.gl_pathc] = NULL;
pid_t pid = fork();
if (pid == 0) {
execvp(cmdargs[0], cmdargs);
} else {
wait(NULL);
printf("Child terminates\n");
}
globfree(&result);
return 0;
}
Upvotes: 0
Reputation: 20901
The asterisk pattern *
is carried on by the shell, but by the ls
.
You can use exec
with sh
, for example.
Editing over the OP’s response,
Obtain all files without using *.c
in a string array and filter the strings as you wish.
Upvotes: 0
Reputation: 488
GLOB pattern is expanded by shell, not the ls
itself.
You may achieve what you want by creating a subshell via exec.
Here's an example of that:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main() {
char *cmdargs[] = { "sh", "-c", "ls -l *.c", NULL };
pid_t pid;
pid = fork();
if (pid == 0) {
execvp(cmdargs[0], cmdargs);
} else {
wait(NULL);
printf("Child terminates\n");
}
return 0;
}
You may also employ system(3)
for this if you want.
Upvotes: 1