NSTask NSPipe - помощь в командной строке c

Вот мой код:

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 в objective-c.

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

Любые идеи?

Илия

Ответ 1

Ошибка 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.

Ответ 2

Решение выше замерзает, потому что оно синхронно. Вызов [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 block в nil; в противном случае вы столкнетесь с высоким уровнем использования ЦП, поскольку чтение никогда не прекратится.

[task setTerminationHandler:^(NSTask *task) {

    // do your stuff on completion

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

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