2010-08-09 4 views
10

Voici mon code:NSTask NSPipe - objectif en ligne de commande c aide

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]; 

Je suis en train de reproduire ceci:

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

mais en utilisant NSTask en c objectif.

Pour une raison quelconque, quand je lance ce code, stringRead, ne renvoie rien. Il devrait retourner ce que terminal retourne quand je lance le fichier .sh. Correct?

Des idées?

Elijah

+0

Etes-vous sûr que le script server.sh est émis en sortie standard? Peut-être que vous devriez également connecter stderr et voir si cela contient quelque chose. Vous pouvez également prendre en compte la lecture des données du tube lorsque la tâche est en cours d'exécution, car s'il tente d'imprimer trop sur le tube pendant que vous ne lisez pas, la tâche se bloque la prochaine fois. il essaie de sortir quoi que ce soit. –

+0

Je ne suis pas sûr. Pouvez-vous me montrer un exemple? Oui, j'ai supprimé [la version de tâche] et [task waitUntilExit]. Même problème. – objectiveccoder001

+0

Vérifiez-vous le contenu de stringRead par programme (ou dans gdb), ou essayez-vous de les imprimer en utilisant NSLog ou quelque chose? Si vous utilisez NSLog et que vous ne voyez aucune sortie, consultez le journal de la console dans Applications> Utilitaires pour votre sortie. Les scripts shell s'exécutent lorsque NSTask peut faire en sorte que la sortie de la console Xcode cesse de fonctionner.À part ça, je seconde l'opinion de Kevin pour vérifier aussi s'il y a quelque chose sur l'erreur standard (il suffit d'ajouter un second tuyau et de définir cela comme une erreur standard de votre tâche), et de ne pas compter sur le tampon la sortie de votre tâche. – puzzle

Répondre

19

Xcode Bug
Il y a un bug dans Xcode qu'il arrête d'imprimer toute sortie après une nouvelle tâche en utilisant la sortie standard est lancée (elle rassemble toutes les sorties, mais n'imprime plus rien). Vous allez devoir appeler [task setStandardInput:[NSPipe pipe]] pour l'afficher à nouveau (ou bien, la tâche s'imprime sur stderr au lieu de stdout).


Suggestion pour le code 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

Il semble que ce soit gel mon code aussi ... hein ... d'autres idées? – objectiveccoder001

+0

Et, j'ai essayé de mettre en écho "bonjour monde" il est retourné vide .... et la date est restée vierge. – objectiveccoder001

+0

Même avec '[serveur setStandardInput: [NSPipe pipe]]'? C'est un peu étrange. Avez-vous copié mon code verbatim? Essayez-le, et voyez si cela fonctionnera avec un fichier qui contient juste 'echo" Hello World "; pwd | ls'. Si cela ne fonctionne toujours pas, veuillez nous indiquer quelle version de Xcode vous utilisez, et voir si l'écriture de la chaîne dans le fichier produit une sortie (il se peut que le terminal Xcode n'imprime plus de sortie). –

9

La solution ci-dessus est le gel, car il est synchrone. L'appel à [server waitUntilExit] bloque la boucle d'exécution jusqu'à ce que les tâches soient terminées.

Voici la solution asynchrone pour obtenir la sortie de la tâche.

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

probablement vous voulez répéter le même ci-dessus pour task.standardError.

IMPORTANT:

Lorsque votre tâche se termine, vous devez définir le bloc readabilityHandler à zéro; Dans le cas contraire, l'utilisation du processeur sera élevée, car la lecture ne s'arrêtera jamais.

[task setTerminationHandler:^(NSTask *task) { 

    // do your stuff on completion 

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

Tout cela est asynchrone (et vous devriez le faire async), de sorte que votre méthode doit avoir un bloc^d'achèvement.

+0

Parfait. Était à la recherche d'un exemple de l'API de bloc. – uchuugaka

Questions connexes