2010-08-13 21 views
1
task = [NSTask new]; 
[task setLaunchPath:@"/bin/sh"]; 
[task setArguments:[NSArray arrayWithObject:@"/applications/jarvis/brain/server.sh"]]; 
[task setCurrentDirectoryPath:@"/"]; 

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

[task launch]; 

NSMutableString *outputString = [NSMutableString string]; 
while ([outputString rangeOfString:@"Jarvis>"].location == NSNotFound) { 
    [outputString appendString:[[[NSString alloc] initWithData:[[outputPipe fileHandleForReading] readDataToEndOfFile] encoding:NSUTF8StringEncoding] autorelease]]; 
    } 

NSArray* substrings = [outputString componentsSeparatedByString:@"Jarvis>"]; 
NSString* finalCharlieOutputNSTask = [substrings lastObject]; 
NSSpeechSynthesizer * syn = [[NSSpeechSynthesizer alloc] init]; 
[syn startSpeakingString:finalCharlieOutputNSTask]; 
self.charlieOutput.stringValue = finalCharlieOutputNSTask; 

Ok, c'est mon code. Il lance un fichier SH et lit la sortie. MAIS, je veux qu'il attende que "Jarvis>" apparaisse dans la chaîne avant de dire et d'imprimer le résultat. Mais, il me semble qu'avec la boucle while, mon code se fige là. Sans cela, il lit la sortie normale du lancement du fichier server.sh, mais le tout. Des idées pour lesquelles cela ne fonctionne pas?Problème de code - objectif c - attendre que la valeur de chaîne apparaisse dans la valeur de chaîne

Voici le fichier Server.sh:

echo Starting Jarvis Program D. 
ALICE_HOME=. 
SERVLET_LIB=lib/servlet.jar 
ALICE_LIB=lib/aliceserver.jar 
JS_LIB=lib/js.jar 

# Set SQL_LIB to the location of your database driver. 
SQL_LIB=lib/mysql_comp.jar 

# These are for Jetty; you will want to change these if you are using a different http server. 
HTTP_SERVER_LIBS=lib/org.mortbay.jetty.jar 

PROGRAMD_CLASSPATH=$SERVLET_LIB:$ALICE_LIB:$JS_LIB:$SQL_LIB:$HTTP_SERVER_LIBS 
java -classpath $PROGRAMD_CLASSPATH -Xms64m -Xmx128m org.alicebot.server.net.AliceServer $1 

Répondre

1

Elijah, modifiez votre code pour ressembler à ceci:

... 
[task launch]; 

NSMutableString *outputString = [NSMutableString string]; 
while ([outputString rangeOfString:@"Jarvis>"].location == NSNotFound) { 
    [outputString appendString:[[[NSString alloc] initWithData:[[outputPipe fileHandleForReading] readDataToEndOfFile] encoding:NSUTF8StringEncoding] autorelease]; 
} 

if ([task isRunning]) { 
    [task terminate]; 
} 

NSArray *subStrings = [outputString componentsSeparatedByString:@"Jarvis>"]; 
... 

Ce code dans la boucle successivement lire les données de sortie de votre fichier et l'ajouter à la sortie de courant, et d'arrêter la lecture lorsque @ "Jarvis> "est trouvé (il va aussi tuer la tâche après qu'un @" Jarvis> "soit trouvé, donc il ne continue pas à tourner pour toujours).

+0

BAH! Non, il gèle toujours à la boucle while. Je poste mon code actuel dans ma question. Des idées? – objectiveccoder001

+0

En outre, comme je l'ai déjà dit: Il me semble que lorsque je vérifie la chaîne de sortie avant la boucle while, je reçois le message "Starting program G" qui est un écho dans le fichier .sh. MAIS, pendant la boucle while, je vérifie la valeur de la chaîne de sortie, et elle renvoie la même chose ... aucune autre configuration ... juste l'écho. Je le vérifie avec NSRunAlertPanel() – objectiveccoder001

+0

En plus du 'echo' d'origine, comment est l'impression de votre fichier bash sur stdout? Y a-t-il d'autres 'échos 'censés fonctionner? Quelle est la sortie lorsque vous exécutez le fichier bash à partir du Terminal? L'utilisateur est-il censé entrer une entrée? –

1

Vous voulez mettre la readDataToEndOfFile dans la boucle. Sinon, il lit les données une fois, vérifie l'existence de votre chaîne, puis boucle à jamais s'il ne la trouve pas dans cette première lecture.

1

Peut-être essayer le rinçage NSPipe le long des lignes de code publiées dans l'article:

"NSTasks, NSPipes, et lors de la lecture ... blocages",

http://dev.notoptimal.net/2007/04/nstasks-nspipes-and-deadlocks-when.html

Une autre approche pourrait tester l'utilisation de NSTask & NSUnbufferedIO.

Vous trouverez un exemple de code dans le livre "Cocoa Programming" de Don Yacktman.

# http://www.cocoaprogramming.net 
# http://www.cocoaprogramming.net/CocoaProgramming-20021010.tgz 

open -e CocoaProgramming-20021010/Chapter\ 24/Animal/AnimalController.h \ 
     CocoaProgramming-20021010/Chapter\ 24/Animal/AnimalController.m \ 
     CocoaProgramming-20021010/Chapter\ 24/Calendar/CalendarController.m 

# for yet another try with sample code using waitForDataInBackgroundAndNotify see: 
# http://cocoawithlove.com/2009/05/invoking-other-processes-in-cocoa.html 

open -e OpenFileKiller/NSTask+OneLineTasksWithOutput.m 
# --> [standardOutputFile waitForDataInBackgroundAndNotify]; 
0

Pour les non-bloquant le code IO pour NSTask & NSFileManager voir aussi le code source de MÉDECIN:

# http://www.stone.com/DOCtor/ 
# http://www.stone.com/DOCtor/DOCtor.tar.gz 

open -e DOCTor/NSFileHandle_CFRNonBlockingIO.h \ 
     DOCTor/NSFileHandle_CFRNonBlockingIO.m \ 
     DOCTor/NSFileManager-Extensions.h \ 
     DOCTor/NSFileManager-Extensions.m 

Notez également que de nombreux programmes de ligne de commande (interne) tampon de bloc leur STDOUT si stdout est un tuyau et non un terminal interactif (tty). Pour cette raison, certains programmes de ligne de commande ont des options spéciales pour mettre en ligne leur sortie, indépendamment de l'envoi de la sortie vers un tube ou un tty.

tcpdump -l 
grep --line-buffered 
...