2010-08-09 7 views
10

Hier ist mein Code:NSTask NSPipe - Ziel c Befehlszeilenhilfe

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

Also das ich versuche zu replizieren:

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

aber mit NSTask in Objective-c.

Aus irgendeinem Grund, wenn ich diesen Code ausführen, StringRead, gibt nichts zurück. Es sollte zurückgeben, welches Terminal zurückkehrt, wenn ich die .sh-Datei starte. Richtig?

Irgendwelche Ideen?

Elijah

+0

Sind Sie sicher, dass das Skript server.sh auf dem Standardausgang ausgegeben wird? Vielleicht sollten Sie stderr auch anschließen und sehen, ob das etwas enthält. Sie können auch das Lesen von Daten aus der Pipe während der Ausführung der Aufgabe in Erwägung ziehen, da die Task beim nächsten Mal aufhängt, wenn sie beim Lesen zu viel Druck auf die Pipe ausübt und der Puffer voll wird Es versucht alles auszugeben. –

+0

Ich bin mir nicht sicher. Kannst du mir ein Beispiel zeigen? Ja, ich habe [Aufgabenfreigabe] und [Aufgabe waitUntilExit] entfernt. Gleiches Problem. – objectiveccoder001

+0

Überprüfen Sie den Inhalt von StringRead programmgesteuert (oder in gdb), oder versuchen Sie, sie mit NSLog oder etwas auszudrucken? Wenn Sie NSLog verwenden und überhaupt keine Ausgabe sehen, überprüfen Sie das Konsolenprotokoll in Anwendungen> Dienstprogramme für Ihre Ausgabe. Shell-Skripts werden ausgeführt, wenn NSTask die Ausgabe der Xcode-Konsole stoppen kann. Zweitens, Kevins Meinung zu überprüfen, ob es etwas auf Standard-Fehler ist (fügen Sie einfach eine zweite Pipe und legen Sie das als Standardfehler Ihrer Aufgabe), und nicht auf die Pipe in der Lage sein, alle zu puffern die Ausgabe Ihrer Aufgabe. – puzzle

Antwort

19

Xcode Bug
ein Fehler in Xcode Es gibt, die es von Druck keine Ausgabe nach einem hält eine neue Aufgabe Standardausgabe mit gestartet wird (es sammelt alle Ausgaben, aber nicht mehr druckt alles). Sie müssen [task setStandardInput:[NSPipe pipe]] aufrufen, damit die Ausgabe wieder angezeigt wird (oder die Aufgabe statt stdout in stderr ausgeben).


Vorschlag für die endgültige Code:

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

Es scheint, als ob dies auch meinen Code einfriert ... huh ... irgendwelche anderen Ideen? – objectiveccoder001

+0

Und ich habe versucht, in Echo "Hallo Welt" zu schreiben es leer zurückkehrte .... und Datum zurückgebrochen leer. – objectiveccoder001

+0

Auch mit '[Server setStandardInput: [NSPipe pipe]]'? Das ist ein bisschen seltsam. Hast du meinen Code wörtlich kopiert? Probieren Sie es aus und prüfen Sie, ob es mit einer Datei funktioniert, die nur 'echo" Hello World "enthält; pwd | ls. Wenn es immer noch nicht funktioniert, teilen Sie uns bitte mit, welche Version von Xcode Sie verwenden, und sehen Sie, ob das Schreiben der Zeichenfolge in eine Datei eine Ausgabe erzeugt (es könnte einfach sein, dass das Xcode-Terminal keine Ausgabe mehr druckt). –

9

Die Lösung oben friert, weil es synchron ist. Anruf an [server waitUntilExit] blockiert die Laufschleife, bis die Aufgaben erledigt sind.

Hier ist die asynchrone Lösung für die Ausgabe der Aufgabe.

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

Wahrscheinlich wollen Sie die gleiche oben für task.standardError wiederholen.

WICHTIG:

Wenn Ihre Aufgabe beendet, müssen Sie readabilityHandler Block auf Null gesetzt; Andernfalls wird eine hohe CPU-Auslastung auftreten, da der Lesevorgang nie beendet wird.

Dies ist alles asynchron (und Sie sollten es async tun), also sollte Ihre Methode einen^Abschlussblock haben.

+0

Perfekt. War auf der Suche nach einem Beispiel für die Block-API. – uchuugaka