2010-08-09 7 views
10

Aquí está mi código:NSTask NSPipe - comando objetivo c línea de ayuda

task = [[NSTask alloc] init]; 
[task setCurrentDirectoryPath:@"/applications/jarvis/brain/"]; 
[task setLaunchPath:@"/applications/jarvis/brain/server.sh"]; 

NSPipe * out = [NSPipe pipe]; 
[task setStandardOutput:out]; 

[task launch]; 
[task waitUntilExit]; 
[task release]; 

NSFileHandle * read = [out fileHandleForReading]; 
NSData * dataRead = [read readDataToEndOfFile]; 
NSString * stringRead = [[[NSString alloc] initWithData:dataRead encoding:NSUTF8StringEncoding] autorelease]; 

así que estoy tratando de replicar esto:

cd /applications/jarvis/brain/ 
./server.sh 

pero utilizando NSTask en Objective-C.

Por alguna razón, sin embargo, cuando ejecuto este código, stringRead, no devuelve nada. Debería devolver qué terminal está devolviendo cuando ejecute el archivo .sh. ¿Correcto?

¿Alguna idea?

Elías

+0

¿Está seguro de que la secuencia de comandos server.sh se ejecuta en salida estándar? Tal vez deberías conectar stderr también y ver si contiene algo. También le conviene considerar leer los datos del conducto mientras se está ejecutando la tarea, porque si intenta imprimir demasiado en el conducto mientras no está leyendo y el búfer se llena, la tarea se bloqueará la próxima vez intenta dar salida a cualquier cosa. –

+0

No estoy seguro. ¿Puedes mostrarme un ejemplo? Sí, eliminé [publicación de tarea] y [tarea waitUntilExit]. El mismo problema. – objectiveccoder001

+0

¿Está revisando los contenidos de stringRead programmatically (o en gdb), o está intentando imprimirlos usando NSLog o algo así? Si está utilizando NSLog y no ve ninguna salida, vaya a la sesión de la Consola en Aplicaciones> Utilidades para su salida. Los scripts de Shell ejecutados como NSTask pueden hacer que la salida de la consola de Xcode deje de funcionar. Aparte de eso, apoyo la opinión de Kevin para verificar si hay algo en el error estándar (simplemente agregue un segundo conducto y configurarlo como un error estándar de su tarea), y para no confiar en que el tubo pueda almacenar todos la salida de tu tarea. – puzzle

Respuesta

19

Xcode Bug
Hay un insecto en Xcode que detenga la impresión de cualquier salida después de una se pone en marcha una nueva tarea utilizando la salida estándar (que recoge toda la producción, pero ya no se imprime nada). Deberá llamar al [task setStandardInput:[NSPipe pipe]] para que muestre la salida nuevamente (o, alternativamente, hacer que la tarea se imprima en stderr en lugar de stdout).


sugerencia para código final:

NSTask *server = [NSTask new]; 
[server setLaunchPath:@"/bin/sh"]; 
[server setArguments:[NSArray arrayWithObject:@"/path/to/server.sh"]]; 
[server setCurrentDirectoryPath:@"/path/to/current/directory/"]; 

NSPipe *outputPipe = [NSPipe pipe]; 
[server setStandardInput:[NSPipe pipe]]; 
[server setStandardOutput:outputPipe]; 

[server launch]; 
[server waitUntilExit]; // Alternatively, make it asynchronous. 
[server release]; 

NSData *outputData = [[outputPipe fileHandleForReading] readDataToEndOfFile]; 
NSString *outputString = [[[NSString alloc] initWithData:outputData encoding:NSUTF8StringEncoding] autorelease]; // Autorelease optional, depending on usage. 
+0

Parece que esto también congela mi código ... ¿eh ... alguna otra idea? – objectiveccoder001

+0

Y, traté de poner en eco "hola mundo", volvió en blanco .... y fecha retured en blanco. – objectiveccoder001

+0

Incluso con '[server setStandardInput: [NSPipe pipe]]'? Eso es un poco extraño. ¿Copiaste mi código textualmente? Pruébalo y ve si funciona con un archivo que solo contenga "echo" Hello World "; pwd | ls'. Si aún no funciona, díganos qué versión de Xcode está usando y vea si escribir la cadena en un archivo produce algún resultado (podría ser simplemente que el terminal Xcode no imprimiera más salidas). –

9

La solución anterior es la congelación porque es síncrona. Llamar al [server waitUntilExit] bloquea el ciclo de ejecución hasta que se completen las tareas.

Aquí está la solución asíncrona para obtener la salida de la tarea.

task.standardOutput = [NSPipe pipe]; 
[[task.standardOutput fileHandleForReading] setReadabilityHandler:^(NSFileHandle *file) { 
    NSData *data = [file availableData]; // this will read to EOF, so call only once 
    NSLog(@"Task output! %@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]); 

    // if you're collecting the whole output of a task, you may store it on a property 
    [self.taskOutput appendData:data]; 
}]; 

Probablemente desea repetir la misma por encima de task.standardError.

IMPORTANTE:

Cuando su tarea termina, usted tiene que fijar el bloque readabilityHandler a cero; de lo contrario, encontrará un uso elevado de la CPU, ya que la lectura nunca se detendrá.

[task setTerminationHandler:^(NSTask *task) { 

    // do your stuff on completion 

    [task.standardOutput fileHandleForReading].readabilityHandler = nil; 
    [task.standardError fileHandleForReading].readabilityHandler = nil; 
}]; 

Esto es todo asíncrono (y debe hacerlo asíncrono), por lo que su método debe tener un bloque finalización ^.

+0

Perfecto. Estaba buscando un ejemplo del bloque API. – uchuugaka

Cuestiones relacionadas