Comment puis-je exécuter un script Shell à partir de C sous Linux?
Cela dépend de ce que vous voulez faire avec le script (ou tout autre programme que vous souhaitez exécuter).
Si vous voulez simplement exécuter le script system
est la chose la plus simple à faire, mais il fait aussi d'autres choses, y compris exécuter un Shell et le faire exécuter la commande (/ bin/sh sous la plupart des * nix).
Si vous souhaitez alimenter le script Shell via son entrée standard ou consommer sa sortie standard, vous pouvez utiliser popen
(et pclose
) pour configurer un canal. Cela utilise également le shell (/ bin/sh sous la plupart des * nix) pour exécuter la commande.
Les deux sont des fonctions de bibliothèque qui font beaucoup de choses sous le capot, mais si elles ne répondent pas à vos besoins (ou si vous voulez simplement expérimenter et apprendre), vous pouvez également utiliser directement les appels système. Cela vous permet également d'éviter que le shell (/ bin/sh) n'exécute votre commande pour vous.
Les appels système d'intérêt sont fork
, execve
et waitpid
. Vous souhaiterez peut-être utiliser l'un des wrappers de bibliothèque autour de execve
(tapez man 3 exec
pour une liste). Vous pouvez également utiliser l'une des autres fonctions d'attente (man 2 wait
les a tous). De plus, vous pouvez être intéressé par les appels système clone
et vfork
qui sont liés à fork.
fork
duplique le programme actuel, où la seule différence principale est que le nouveau processus obtient 0 retourné de l'appel à fork. Le processus parent obtient l'ID de processus du nouveau processus (ou une erreur) retourné.
execve
remplace le programme actuel par un nouveau programme (en gardant le même identifiant de processus).
waitpid
est utilisé par un processus parent pour attendre la fin d'un processus enfant particulier.
La séparation des étapes fork et execve permet aux programmes d'effectuer une configuration pour le nouveau processus avant sa création (sans se gâcher). Il s'agit notamment de modifier l'entrée, la sortie et stderr standard pour qu'ils soient différents de ceux du processus parent utilisé, de changer l'utilisateur ou le groupe du processus, de fermer les fichiers dont l'enfant n'aura pas besoin, de changer la session ou de changer les variables d'environnement.
Vous pouvez également être intéressé par les pipe
et dup2
appels système. pipe
crée un tube (avec un descripteur de fichier d'entrée et de sortie). dup2
duplique un descripteur de fichier en tant que descripteur de fichier spécifique (dup
est similaire mais duplique un descripteur de fichier au descripteur de fichier le plus bas disponible).
Vous pouvez utiliser system
:
system("/usr/local/bin/foo.sh");
Cela se bloquera lors de son exécution à l'aide de sh -c
, puis renvoyez le code d'état.
Si vous êtes d'accord avec POSIX, vous pouvez également utiliser popen()
/ pclose()
#include <stdio.h>
#include <stdlib.h>
int main(void) {
/* ls -al | grep '^d' */
FILE *pp;
pp = popen("ls -al", "r");
if (pp != NULL) {
while (1) {
char *line;
char buf[1000];
line = fgets(buf, sizeof buf, pp);
if (line == NULL) break;
if (line[0] == 'd') printf("%s", line); /* line includes '\n' */
}
pclose(pp);
}
return 0;
}
Un moyen simple est .....
#include <stdio.h>
#include <stdlib.h>
#define SHELLSCRIPT "\
#/bin/bash \n\
echo \"hello\" \n\
echo \"how are you\" \n\
echo \"today\" \n\
"
/*Also you can write using char array without using MACRO*/
/*You can do split it with many strings finally concatenate
and send to the system(concatenated_string); */
int main()
{
puts("Will execute sh with the following script :");
puts(SHELLSCRIPT);
puts("Starting now:");
system(SHELLSCRIPT); //it will run the script inside the c code.
return 0;
}
Dites merci à
Yoda @ http://www.unix.com/programming/216190-putting-bash-script-c-program.html
Je préfère fork + execlp pour un contrôle "plus fin" comme Doron l'a mentionné. Exemple de code illustré ci-dessous.
Stockez votre commande dans un tableau de paramètres char et un espace malloc pour le résultat.
int fd[2];
pipe(fd);
if ( (childpid = fork() ) == -1){
fprintf(stderr, "FORK failed");
return 1;
} else if( childpid == 0) {
close(1);
dup2(fd[1], 1);
close(fd[0]);
execlp("/bin/sh","/bin/sh","-c",parameters,NULL);
}
wait(NULL);
read(fd[0], result, RESULT_SIZE);
printf("%s\n",result);
Si vous avez besoin d'un contrôle plus précis, vous pouvez également suivre la route fork
pipe
exec
. Cela permettra à votre application de récupérer les données issues du script Shell.