2010-09-17 29 views

Respuesta

38

Depende de lo que quiere hacer con el guión (o cualquier otro programa que desea ejecutar).

Si solo desea ejecutar el script system es lo más fácil de hacer, pero también hace otras cosas, incluso ejecutar un shell y ejecutar el comando (/ bin/sh en la mayoría de * nix).

Si desea alimentar el script de shell a través de su entrada estándar o consumir su salida estándar, puede usar popen (y pclose) para configurar un conducto. Esto también usa el shell (/ bin/sh en la mayoría de * nix) para ejecutar el comando.

Ambas son funciones de la biblioteca que hacen mucho bajo el capó, pero si no satisfacen sus necesidades (o si simplemente desea experimentar y aprender) también puede usar las llamadas al sistema directamente. Esto también le permite evitar que el shell (/ bin/sh) ejecute su comando por usted.

Las llamadas al sistema de interés son fork, execve y waitpid. Es posible que desee utilizar uno de los contenedores de la biblioteca alrededor del execve (escriba man 3 exec para obtener una lista de ellos). También es posible que desee utilizar una de las otras funciones de espera (man 2 wait tiene todas). Además, puede que le interesen las llamadas al sistema clone y vfork que están relacionadas con la horquilla.

fork duplica el programa actual, donde la única diferencia principal es que el nuevo proceso obtiene 0 devuelto desde la llamada a la bifurcación. El proceso principal obtiene el identificador del proceso del proceso nuevo (o un error) devuelto.

execve reemplaza el programa actual con un nuevo programa (manteniendo el mismo ID de proceso).

waitpid es utilizado por un proceso principal para esperar a que finalice un proceso hijo en particular.

Tener los pasos de fork y execve por separado permite a los programas realizar alguna configuración para el nuevo proceso antes de que se cree (sin estropearse). Esto incluye cambiar la entrada, salida y stderr estándar para que sean archivos diferentes al proceso principal utilizado, cambiar el usuario o grupo del proceso, cerrar archivos que el niño no necesitará, cambiar la sesión o cambiar las variables del entorno.

También le pueden interesar las llamadas al sistema pipe y dup2. pipe crea una tubería (con un descriptor de archivo tanto de entrada como de salida).dup2 duplica un descriptor de archivo como un descriptor de archivo específico (dup es similar pero duplica un descriptor de archivo al descriptor de archivo disponible más bajo).

+2

También vale la pena señalar que la horquilla() es bastante barata, ya que la memoria es de copia en escritura y no se duplica tan pronto como el programa se bifurca. – Cercerilla

+0

Soy un gran entusiasta de fork/exec: le permite evitar incertidumbres entorno a lo que se va a ejecutar. ¿Pero puede usarlo en scripts de shell directamente? Como dices, al usar exec, "evitas que el shell (/ bin/sh) ejecute tu comando por ti"; ¿No necesita ejecutar/bin/sh para ejecutar un script de shell? –

+1

@Tom Anderson: Si el script de shell tiene permisos de ejecución configurados para el usuario efectivo y tiene una primera línea apropiada de shabang que enumera un archivo que el usuario efectivo también tiene permiso para ejecutar y tampoco es un script de algún tipo, entonces el kernel llame al archivo que figura en la línea de shabang con el archivo de script. Si el shabang del script fuera '#!/Bin/csh', entonces'/bin/sh' no se ejecutaría en el escenario fork/exec. Si fuera '#!/Bin/sh', lo haría en el escenario fork/exec, pero con la versión' system' '/ bin/sh' se ejecutaría dos veces para este script. – nategoose

23

Puede utilizar system:

system("/usr/local/bin/foo.sh"); 

Esto bloqueará mientras se ejecuta utilizando sh -c, a continuación, devolver el código de estado.

+3

1 No se olvide de incluir '' (http: // linux.die.net/man/3/system) – pmg

+1

... asumiendo que tiene un bit ejecutable y una línea shebang. En general, 'system ("/bin/sh/usr/local/bin/foo.sh ");'. Sí, esto en realidad llama al caparazón dos veces. –

1

Si necesita más control de precisión, también puede ir a la ruta forkpipeexec. Esto permitirá que su aplicación recupere los datos generados desde el script de shell.

15

Si estás bien con POSIX, también se puede utilizar 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; 
} 
+0

Gracias por este código de muestra. –

1

Prefiero fork + execlp para el control de "grado más fino" como se menciona en doron. Ejemplo de código que se muestra a continuación.

Almacene su comando en los parámetros de una matriz char, y malloc espacio para el resultado.

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); 
+0

'close (1);' no es necesario ya que dup2() cierra el newfd por sí mismo antes de volver a asignarlo. – FedericoCapaldo

2

Una forma sencilla es .....

#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; 
} 

decir gracias a
Yoda @http://www.unix.com/programming/216190-putting-bash-script-c-program.html

Cuestiones relacionadas