Использование 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;
 }
Другие вопросы по тегам