简体   繁体   中英

Commands like “ls -l” not executing in execl, whereas in execvp it works

Using the code below in the execl variant, ls works, but ls -l does not work, but in my execvp approach ls and ls-l works. The reason why I adopted the execl approach is because the path of the binaries could differ whereas execvp did not provide me that feature. Ideally I want execl to also work on ls -l , but right now it does not work on ls -l . I tried reading the man pages but it did not help.

void child(int argc, char *argv[MAX_ARGS])
{
        execvp(argv[0], argv);
}


void child(char *argv[], char* path)
{
        execl(path, argv, NULL);
}

With execl() , you have to list the arguments one by one; it is only useful if you know exactly what you're going to execute ahead of time:

execl("/bin/ls", "ls", "-l", (char *)0);
execl("/bin/sh", "sh", "-c", "ls -l", (char *)0);
execl("/bin/ls", "pink elephants", "-l", (char *)0);

Etc.

If you don't know how many arguments you'll have to deal with, use execvp() or one of the other members of the execv*() family. Also note that you have to specify the path of the command; execvp() does a search down $PATH , but execl() does not. Also note that you get to choose the value passed as argv[0] .

The reason why I adopted the execl() approach is because the path of the binaries could differ whereas execvp() did not provide me that feature.

I'm not sure what you mean here. With execvp() , you can specify:

char *argv[] = { "ls", "-l", 0 };
execvp(argv[0], argv);
execv("/bin/ls", argv);

The execvp() will search for ls on $PATH and execute the first program found that matches. The second will execute /bin/ls without looking at $PATH at all.

char *argv[] = { "/bin/ls", "-l", 0 };

execv(argv[0], argv);
execvp(argv[0], argv);

Either of these will work; the second won't use a PATH-based search because the executable name ( argv[0] ) contains a slash.


What confuses me is that in execvp(argv[0], argv); why are we passing the entire argv as the 2nd parameter? So suppose argv[0] was "ls -l" , why do we have to pass the entire argv as the 2nd parameter?

Supposing argv[0] contains "ls -l" , you have a problem. Most systems do not have a file " /bin/ls -l " or " /usr/bin/ls -l " (where the blank is part of the name), but that's what you'd be seeking to execute.

The exec*() functions are the low-level functions for executing processes. The first argument designates the program to be run (normally, a binary; sometimes a script with a shebang line such as #!/bin/sh as the first line). In the case of execv() or execvp() or execve() or execvpe() , the second argument is the vector of arguments, just like the main() function receives a vector of arguments (or argument vector, hence argv ). This is a null-terminated list of the arguments to the program. If you want to execute the ls command with the option -l , then you need to specify in the argv the three(!) values "ls" , "-l" and a null pointer:

char argv[] = { "ls", "-l", 0 };

With the execl*() functions, you specify the program to be run as the first argument, and this is then followed by the argument vector written out:

execl("/bin/ls", "ls", "-l", (char *)0);

If you have 10 arguments, you have to write out 10 arguments (plus the null pointer).

In the exec*() functions, the names contain:

  • l — list format arguments
  • v — vector format arguments
  • p — do PATH lookup on the program (if the given name does not contain a slash)
  • e — take a vector of environment variables too

These combine to give:

  • execl()
  • execv()
  • execlp()
  • execle()
  • execvp()
  • execve()

It is occasionally a tad irksome that there isn't an execlpe() and execvpe() (but see the Linux extension execvpe(3) ). It is also traditional for the man 2 exec pages to omit some of these from the synopsis but mention them in the body of the manual page — a tradition/legacy dating back to at least 7th Edition UNIX™ in 1979 (and perpetuated at least until RHEL 5 Linux and Mac OS X 10.7.5; the man 2 execl page mentions execve() but does not list it in the Synopsis section). The other exec*() functions can all be built atop execve() — that is the fundamental function in the set (and is listed as execve(2) in the Linux manuals as a result).

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