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), поэтому ваш метод должен иметь блок завершения ^.