NSTask NSPipe - задача c справкой по командной строке - PullRequest
10 голосов
/ 10 августа 2010

Вот мой код:

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

Итак, я пытаюсь повторить это:

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

но с использованием NSTask в target-c.

По какой-то причине, когда я запускаю этот код, stringRead ничего не возвращает. Он должен вернуть то, что возвращает терминал, когда я запускаю .sh файл. Правильно?

Есть идеи?

Элайджа

Ответы [ 2 ]

19 голосов
/ 12 августа 2010

Ошибка XCode
В XCode есть ошибка, из-за которой он не может печатать любой вывод после запуска новой задачи с использованием стандартного вывода (он собирает все выходные данные, но больше ничего не печатает).Вам нужно будет вызвать [task setStandardInput:[NSPipe pipe]], чтобы он снова показал вывод (или, наоборот, вывести задачу на stderr вместо stdout).


Предложение для окончательного кода:

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.
10 голосов
/ 29 апреля 2013

Решение выше зависает, потому что это синхронно.Вызов [server waitUntilExit] блокирует цикл выполнения до тех пор, пока задачи не будут выполнены.

Вот асинхронное решение для получения вывода задачи.

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

Возможно, вы хотите повторить то же самое выше для task.standardError.

ВАЖНО:

Когда ваша задача завершается, вы должны установить для блока readabilityHandler значение nil;в противном случае вы столкнетесь с высокой загрузкой ЦП, поскольку чтение никогда не прекратится.

[task setTerminationHandler:^(NSTask *task) {

    // do your stuff on completion

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

Это все асинхронно (и вы должны делать это асинхронно), поэтому у вашего метода должен быть блок завершения ^.1015 *

...