2008-09-04 30 views
44

Tengo una utilidad que genera una lista de archivos requeridos por un juego. ¿Cómo puedo ejecutar esa utilidad dentro de un programa en C y obtener su resultado para poder actuar dentro del mismo programa?¿Cómo puedo ejecutar un programa externo desde C y analizar su salida?

ACTUALIZACIÓN: Buena llamada en la falta de información. La utilidad escupe una serie de cadenas, y se supone que es completamente portátil en Mac/Windows/Linux. Tenga en cuenta que estoy buscando una forma programática para ejecutar la utilidad y conservar su salida (que va a stdout).

+0

ver también http://stackoverflow.com/questions/125828/capturing-stdout-from-a-system-command-optimally – rogerdpack

+0

Si también desea stderr, puede redirigir, por ejemplo, llamar a ls nonexistant-name 2> & 1 – Vic

+5

Esto no es un duplicado; la pregunta vinculada es ** específica de C++ **, mientras que esta pregunta es acerca de ** C **. –

Respuesta

45

Para problemas simples en entornos Unix-ish, pruebe popen().

Desde la página de hombre:

El popen() función abre un proceso mediante la creación de un tubo, que se bifurcan y la invocación de la cáscara.

Si utiliza el modo de lectura, esto es exactamente lo que solicitó. No sé si está implementado en Windows.

Para problemas más complicados, desea consultar la comunicación entre procesos.

+20

Algunos ejemplos de cómo usar correctamente 'popen()' sería bueno. –

+1

He agregado un enlace a la página de manual de Open Group para la función, que incluye un ejemplo. Básicamente, 'popen' te muestra un puntero de archivo muy parecido a' fopen'. Es solo que le permite escribir en la entrada estándar o leer desde la salida estándar de un programa en lugar de interactuar con un archivo de disco. Esa es la filosofía de "todo es un archivo" de Unix en el trabajo. Algunas implementaciones amplían el estándar al permitir la comunicación bidireccional. – dmckee

+0

[La respuesta de Thi] (http://stackoverflow.com/a/53372/119527) indica que 'popen' está disponible en Windows. –

7

Bueno, suponiendo que está en una línea de comando en un entorno de Windows, puede utilizar las canalizaciones o los redireccionamientos de línea de comando. Por ejemplo,

commandThatOutputs.exe > someFileToStoreResults.txt 

o

commandThatOutputs.exe | yourProgramToProcessInput.exe 

Dentro de su programa, usted podría utilizar las funciones de entrada estándar de C para leer la otra salida de programas (scanf, etc.): http://irc.essex.ac.uk/www.iota-six.co.uk/c/c1_standard_input_and_output.asp. También puede usar el ejemplo de archivo y usar fscanf. Esto también debería funcionar en Unix/Linux.

Esta es una pregunta muy genérica, es posible que desee incluir más detalles, como qué tipo de salida es (solo texto o un archivo binario) y cómo desea procesarla.

Editar: ¡Aclaración de Hooray!

Redireccionando STDOUT parece ser problemático, he tenido que hacerlo en .NET, y me dio todo tipo de dolores de cabeza. Parece que la forma correcta de C es engendrar un proceso secundario, obtener un puntero a un archivo y, de repente, me duele la cabeza.

Aquí hay un truco que usa archivos temporales. Es simple, pero debería funcionar. Esto funcionará bien si la velocidad no es un problema (golpear el disco es lento), o si es desechable. Si está creando un programa empresarial, probablemente sea mejor investigar la redirección STDOUT, utilizando lo que otras personas recomendaron.

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

int main(int argc, char* argv[]) 
{ 
    FILE * fptr;     // file holder 
    char c;       // char buffer 


    system("dir >> temp.txt");  // call dir and put it's contents in a temp using redirects. 
    fptr = fopen("temp.txt", "r"); // open said file for reading. 
            // oh, and check for fptr being NULL. 
    while(1){ 
     c = fgetc(fptr); 
     if(c!= EOF) 
      printf("%c", c);  // do what you need to. 
     else 
      break;     // exit when you hit the end of the file. 
    } 
    fclose(fptr);     // don't call this is fptr is NULL. 
    remove("temp.txt");    // clean up 

    getchar();      // stop so I can see if it worked. 
} 

Asegúrese de revisar sus permisos de archivos: en este momento esto va a lanzar simplemente el archivo en el mismo directorio que un exe. Es posible que desee examinar el uso de /tmp en nix, o C:\Users\username\Local Settings\Temp en Vista, o C:\Documents and Settings\username\Local Settings\Temp in 2K/XP. Creo que el /tmp funcionará en OSX, pero nunca he usado uno.

+0

awesome .. :) esto me ayudó .. –

+0

'c' debería ser un' int' porque 'fgetc' devuelve un' int', no un 'char'. –

2

La documentación de MSDN dice Si se usa en un programa de Windows, la función _popen devuelve un puntero de archivo no válido que hace que el programa deje de responder indefinidamente. _popen funciona correctamente en una aplicación de consola. Para crear una aplicación de Windows que redirija las entradas y salidas, consulte Crear un proceso secundario con entrada y salida redirigidas en el SDK de Windows.

0
//execute external process and read exactly binary or text output 
//can read image from Zip file for example 
string run(const char* cmd){ 
    FILE* pipe = popen(cmd, "r"); 
    if (!pipe) return "ERROR"; 
    char buffer[262144]; 
    string data; 
    string result; 
    int dist=0; 
    int size; 
    //TIME_START 
    while(!feof(pipe)) { 
     size=(int)fread(buffer,1,262144, pipe); //cout<<buffer<<" size="<<size<<endl; 
     data.resize(data.size()+size); 
     memcpy(&data[dist],buffer,size); 
     dist+=size; 
    } 
    //TIME_PRINT_ 
    pclose(pipe); 
    return data; 
} 
+2

¿Qué idioma es? Seguramente no C ('string.resize'?) – ugoren

+0

parece C++ :( – gideon

1

Puede utilizar system() como en:

system("ls song > song.txt"); 

donde ls es el nombre del comando para listar el contenido de la canción de la carpeta y song es una carpeta en el directorio actual. El archivo resultante song.txt se creará en el directorio actual.

+0

¿Qué sucede si quiero redirigir otros programas de salida en un archivo? No es un comando –

29

Como han señalado otros, popen() es la forma más estándar. Y puesto que no hay respuesta proporciona un ejemplo utilizando este método, aquí va:

#include <stdio.h> 

#define BUFSIZE 128 

int parse_output(void) { 
    char *cmd = "ls -l";  

    char buf[BUFSIZE]; 
    FILE *fp; 

    if ((fp = popen(cmd, "r")) == NULL) { 
     printf("Error opening pipe!\n"); 
     return -1; 
    } 

    while (fgets(buf, BUFSIZE, fp) != NULL) { 
     // Do whatever you want here... 
     printf("OUTPUT: %s", buf); 
    } 

    if(pclose(fp)) { 
     printf("Command not found or exited with error status\n"); 
     return -1; 
    } 

    return 0; 
} 
+0

No debería' if (pclose (fp)) 'be' if (pclose (fp) == -1) '? –

+2

@CoolGuy: depende de lo que desee.' pclose() 'return' -1' si hubo un error al obtener el estado de salida del comando; de lo contrario, devuelve el estado de salida en sí mismo Como los comandos tradicionalmente establecen el estado de salida '0' para indicar éxito, al marcar' if (pclose (fp)) 'estamos probando los errores en' pclose() 'o en el comando. – MestreLion

Cuestiones relacionadas