Использование 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
Child's PID is 19194. Parent's PID is 19193

person Baelix    schedule 25.09.2012    source источник
comment
Я бы рекомендовал увеличить ваши настройки для предупреждений компилятора. Он должен был сказать вам вернуть int из main. В моей системе он также жаловался на отсутствие #include ‹wait.h›. И ожидание принимает в качестве аргумента целочисленный указатель, а не целое число.   -  person Scooter    schedule 25.09.2012


Ответы (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);
person Scooter    schedule 25.09.2012

Первый аргумент по соглашению должен указывать на имя файла, связанного с исполняемым файлом. Вы хотите выполнить ls, поэтому первый аргумент должен быть /bin/ls, это означает, что код

execv("/bin/ls", argv2);

Вы могли бы попробовать это

person Lyle Malik    schedule 25.09.2012

/* 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(), которая сделает весь поиск за вас.

person wildplasser    schedule 26.09.2012

Первый аргумент для execv() — это не каталог для запуска, а путь к файлу, который вы хотите выполнить. По умолчанию ваша исполняемая программа будет работать в контексте текущего каталога вызывающей программы.

person Marc Cohen    schedule 25.09.2012
comment
Ну, я также пытался запустить его с помощью execv("/prog.c", argv2);, но это тоже не работает. Я не могу жестко указать путь к файлу в программе, потому что путь зависит от того, кто запускает код. Какие-либо предложения? (Извините, это так двусмысленно, мой профессор не совсем первоклассный, если вы понимаете, о чем я). - person Baelix; 25.09.2012
comment
И также попытался создать папку, а затем подпапку, чтобы она была /Lab1/Prog/. Еще ничего :/ - person Baelix; 25.09.2012
comment
/prog.c не является относительным путем — это полный путь к файлу prog.c в корневом каталоге. Кроме того, первым аргументом execv должен быть исполняемый файл, а не исходный файл c. Я смущен тем, что вы пытаетесь сделать здесь. - person Marc Cohen; 25.09.2012
comment
@baelix execv(/prog.c, argv2); попытается запустить файл .c, что не имеет смысла. Основываясь на вашем фактическом описании и коде, который вы разместили, вам просто нужно сделать execv(argv2[0], argv2); Вы скомпилируете и запустите свою собственную программу, как вы уже упоминали: ./prog ls -t -al - person nos; 25.09.2012

Первый аргумент — это абсолютный путь к программе, которую вы хотите запустить; другими словами, первая часть команды, которую вы вводите в терминале. Вы можете найти, где программа, используя команду whereis. Кроме того, функция execv может искать путь для вас, что делает ваш код более переносимым.

person weito    schedule 26.09.2012

Пример кода для справки:

#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;
 }
person parasrish    schedule 07.09.2015