Использование execv (язык C) для запуска команд из командной строки linux
Единственная часть, в которой я до сих пор путаюсь, - это как настроить execv с первым параметром в качестве текущего рабочего каталога. Я пробовал оба "." и "~", ни один из них не выполняет ничего на экране; то же самое для "/." и "/ ~". Я запутался в том, как запустить execv примерно так:
$./prog ls -t -al
И пусть он выполнит команды после выполнения программы (которые хранятся в argv) в текущем каталоге или в том же каталоге, в котором находится файл (который будет зависеть от того, кто его использует).
Мой код:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
void main(int argc, char *argv[])
{
int pid;
int count = 0;
char *argv2[argc+1];
for(count = 0; count < argc-1; count++){
argv2[count] = argv[count+1];
printf("Argv2: %s\n", argv2[count]); //just double checking
argv2[argc-1] = NULL;
}
pid = fork();
if(pid == 0){
printf("Child's PID is %d. Parent's PID is %d\n", (int)getpid, (int)getppid());
execv(".", argv2); //<---- confused here
}
else{
wait(pid);
exit(0);
}
}
Некоторые примеры выходных данных:
$./prog ls -t -al
Argv2: ls
Argv2: -t
Argv2: -al
PID ребенка - 19194. PID родителя - 19193
6 ответов
Я думаю, execv - это то, что требуется для использования. execvp намного лучше, так как он будет искать команды в настройках PATH.
execv(".", argv2); //<---- confused here
...
#include <errno.h>
#include <string.h>
if ( execv(argv2[0],argv2) )
{
printf("execv failed with error %d %s\n",errno,strerror(errno));
return 254;
}
wait(pid);
...
pid_t wait_status = wait(&pid);
Первый аргумент, по соглашению, должен указывать на имя файла, связанное с исполняемым файлом. Вы хотите исполнить ls
поэтому первый аргумент должен быть /bin/ls
это означает, что код
execv("/bin/ls", argv2);
Вы можете попробовать это
/* main() returns int */
int main(int argc, char *argv[])
{
int pid;
pid = fork();
if(pid == 0){
printf("Child's PID is %d. Parent's PID is %d\n"
, (int)getpid, (int)getppid());
execv(argv[1], argv+1);
}
else{
wait(NULL);
exit(0);
}
return 0;
}
ОБНОВЛЕНИЕ: execv() нужен абсолютный путь к исполняемому файлу; для файлов в текущем каталоге вы должны создать этот путь (например, через pwd()). Если вы хотите, чтобы исполняемый файл находился в кэше через переменную среды $PATH, вы можете использовать execvp(), которая выполняет все операции поиска за вас.
Первый аргумент - это абсолютный путь к программе, которую вы хотите запустить; другими словами, первая часть команды, которую вы вводите в терминале. Вы можете найти, где находится программа, используя команду whereis
, Также, execv
Функция может найти путь для вас, что делает ваш код более переносимым.
Первый аргумент execv() - это не каталог для запуска, а путь к файлу, который вы хотите выполнить. По умолчанию ваша exec-ed программа будет работать в контексте текущей директории вызывающей стороны.
Пример кода для вашей справки:
#include <stdio.h>
int main() {
int ret = fork();
if(ret == 0)
{
char *params[4] = {"/bin/ls", "-l",0}; //cmd params filled
int res = execv( "/bin/ls" , params); //parameters for cmd
//int res = execv( "/bin/ls" , NULL); //this is fail case (when child-exit with -1 status can be seen)
printf("\n child exiting (%d) .. \n", res); //on successful execution of cmd, this exit never appears
}
else
{
waitpid(ret,1,0);
printf("parent exiting\n");
}
return 1;
}