web-dev-qa-db-fra.com

Comment exécuter un programme externe dans le code C sous Linux avec des arguments?

Je veux exécuter un autre programme dans le code C. Par exemple, je veux exécuter une commande

./foo 1 2 3

foo est le programme qui existe dans le même dossier, et 1 2 3 sont des arguments. Le programme foo crée un fichier qui sera utilisé dans mon code.

Comment puis-je faire cela?

45
js0823

Pour un moyen simple, utilisez system():

#include <stdlib.h>
...
int status = system("./foo 1 2 3");

system() attendra que foo termine son exécution, puis renverra une variable d'état que vous pourrez utiliser pour vérifier, par exemple, par exemple. exitcode (le code de sortie de la commande est multiplié par 256, divisez donc la valeur renvoyée par system () par celle-ci pour obtenir le code de sortie réel: int exitcode = status / 256).

La page de manuel de wait() (dans la section 2, man 2 wait Sur votre système Linux) répertorie les différentes macros que vous pouvez utiliser pour examiner le statut, les plus intéressantes être WIFEXITED et WEXITSTATUS.

Sinon, si vous avez besoin de lire la sortie standard de foo, utilisez popen(3), qui renvoie un pointeur de fichier (FILE *); interagir avec les entrées/sorties standard de la commande revient alors à lire ou à écrire dans un fichier.

42
Erik

La fonction system appelle un shell pour exécuter la commande. Bien que cela soit pratique, il est bien connu implications pour la sécurité . Si vous pouvez spécifier le chemin du programme ou du script à exécuter et perdre l’indépendance de la plate-forme fournie par system, vous pouvez utiliser un wrapper execve comme illustré dans le exec_prog fonction ci-dessous pour exécuter votre programme de manière plus sécurisée.

Voici comment vous spécifiez les arguments dans l'appelant:

const char    *my_argv[64] = {"/foo/bar/baz" , "-foo" , "-bar" , NULL};

Puis appelez le exec_prog fonctionne comme ceci:

int rc = exec_prog(my_argv);

Ici se trouve le exec_prog une fonction:

static int exec_prog(const char **argv)
{
    pid_t   my_pid;
    int     status, timeout /* unused ifdef WAIT_FOR_COMPLETION */;

    if (0 == (my_pid = fork())) {
            if (-1 == execve(argv[0], (char **)argv , NULL)) {
                    perror("child process execve failed [%m]");
                    return -1;
            }
    }

#ifdef WAIT_FOR_COMPLETION
    timeout = 1000;

    while (0 == waitpid(my_pid , &status , WNOHANG)) {
            if ( --timeout < 0 ) {
                    perror("timeout");
                    return -1;
            }
            sleep(1);
    }

    printf("%s WEXITSTATUS %d WIFEXITED %d [status %d]\n",
            argv[0], WEXITSTATUS(status), WIFEXITED(status), status);

    if (1 != WIFEXITED(status) || 0 != WEXITSTATUS(status)) {
            perror("%s failed, halt system");
            return -1;
    }

#endif
    return 0;
}

Rappelez-vous le comprend:

#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>

Voir publication SE liée pour les situations nécessitant une communication avec le programme exécuté via des descripteurs de fichier tels que stdin et stdout.

34

Vous pouvez utiliser fork() et system() pour que votre programme ne soit pas obligé d'attendre le retour de system().

#include <stdio.h>
#include <stdlib.h>

int main(int argc,char* argv[]){

    int status;

    // By calling fork(), a child process will be created as a exact duplicate of the calling process.
    // Search for fork() (maybe "man fork" on Linux) for more information.
    if(fork() == 0){ 
        // Child process will return 0 from fork()
        printf("I'm the child process.\n");
        status = system("my_app");
        exit(0);
    }else{
        // Parent process will return a non-zero value from fork()
        printf("I'm the parent.\n");
    }

    printf("This is my main program and it will continue running and doing anything i want to...\n");

    return 0;
}
15
Pedro Alves

En C

#include <stdlib.h>

system("./foo 1 2 3");

En C++

#include <cstdlib>

std::system("./foo 1 2 3");

Ensuite, ouvrez et lisez le fichier comme d'habitude.

4
Fred Foo

system() exécute un shell qui est ensuite responsable de l'analyse des arguments et de l'exécution du programme souhaité. Pour exécuter le programme directement, utilisez fork () et exec () (ce que system () utilise pour exécuter le shell ainsi que ce que le shell utilise pour exécuter des commandes).

#include <unistd.h>

int main() {
     if (fork() == 0) {
          /*
           * fork() returns 0 to the child process
           * and the child's PID to the parent.
           */
          execl("/path/to/foo", "foo", "arg1", "arg2", "arg3", 0);
          /*
           * We woundn't still be here if execl() was successful,
           * so a non-zero exit value is appropriate.
           */
          return 1;
     }

     return 0;
}
4
Billy

Que diriez-vous comme ça:

char* cmd = "./foo 1 2 3";
system(cmd);
2
Johan

Voici le moyen d'étendre aux arguments variables les arguments qui ne sont pas codés en dur (bien qu'ils soient encore codés en dur dans cet exemple, mais il devrait être facile de comprendre comment étendre ...):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int argcount = 3;
const char* args[] = {"1", "2", "3"};
const char* binary_name = "mybinaryname";
char myoutput_array[5000];

sprintf(myoutput_array, "%s", binary_name);
for(int i = 0; i < argcount; ++i)
{
    strcat(myoutput_array, " ");
    strcat(myoutput_array, args[i]);
}
system(myoutput_array);
1
Hazok