Как мне получить выходные данные из команды оболочки? - PullRequest
1 голос
/ 16 ноября 2011

Предупреждение новичка Какао!

Я считаю, что следующая команда оболочки - хороший способ определить, запущен ли процесс (1 = запущен, 0 = не запущен):

if [ $(ps -Ac | egrep -o 'ProcessName') ]; then echo 1; else echo 0; fi;

Я могу включить это в Какао с помощью команды "system":

system("if [ $(ps -Ac | egrep -o 'Finder') ]; then echo 1; else echo 0; fi;");

Однако выходные данные направлены в журнал выполнения, и я не могу понять, как захватить результат (1 или 0) в моем коде Какао.

Я попытался реализовать это с помощью NSTask следующим образом:

NSTask *task = [[NSTask alloc] init];
[task setLaunchPath:@"/bin/sh"];
[task setArguments:[NSArray arrayWithObject:@"if [ $(ps -Ac | egrep -o 'Finder') ]; then echo 1; else echo 0; fi;"]];
NSPipe *pipe = [NSPipe pipe];
[task setStandardOutput:pipe];
[task launch];
NSData *data = [[pipe fileHandleForReading] readDataToEndOfFile];
[task waitUntilExit];
[task release];
NSString *output = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog (@"%@", output);
[output release];

Однако это приводит к появлению следующего сообщения об ошибке:

if [$ (ps -Ac | egrep -o 'Finder')];затем эхо 1;еще эхо 0;fi ;: Нет такого файла или каталога

Подскажите, пожалуйста, как я могу правильно реализовать эту команду оболочки таким образом, чтобы я мог захватить вывод (1 или 0) в коде?(Я знаю о других методах определения того, запущен ли процесс, но одна из причин моего вопроса состоит в том, чтобы узнать, как реализовать сценарии оболочки в целом в Какао.)

Большое спасибо за любую помощьс этой проблемой.

Ответы [ 3 ]

3 голосов
/ 16 ноября 2011

Вы делаете это неправильно.Вместо того, чтобы спрашивать «как мне запустить внешний процесс для выполнения X», вы должны спросить «как мне написать код для выполнения X».

Вам не нужно использовать внешний скрипт для получения спискапроцессы.В общем, вы всегда должны пытаться использовать API, а не запускать внешнюю задачу, из соображений производительности и безопасности.

В этом случае вам нужен API-интерфейс sysctl C.

JongAm Park написал оболочку Objective-C для использования sysctl для получения списка запущенных процессов.В комментариях к его сообщению также содержатся хорошие замечания.

Кроме того, вы можете увидеть, как Apple это делает, посмотрев исходный код команды ps.

2 голосов
/ 16 ноября 2011

Роб, спасибо за общий указатель на использование прямого решения в коде, когда это возможно. Я просмотрел упаковку JongAm Park для sysctl, а также исходный код Apple ps. Включение займет некоторое время, но теперь я знаю, где искать прямое решение для получения списка процессов.

shellter и tripleee, спасибо за ваши предложения относительно взаимодействия с командами оболочки. Исходя из ваших предложений, я получил три метода работы (!):

В способе 1 используется код возврата команды system (нет необходимости в egrep -o):

BOOL processIsRunning = system("ps -Ac | grep 'ProcessName' > /dev/null") == 0;

Метод 2 использует NSTask с параметром оболочки -c (примечание -c вместо -e):

NSTask *task = [[NSTask alloc] init];
[task setLaunchPath:@"/bin/sh"];
[task setArguments:[NSArray arrayWithObjects:@"-c",@"ps -Ac | grep 'ProcessName'",nil]];
NSPipe *pipe = [NSPipe pipe];
[task setStandardOutput:pipe];
[task launch];
NSData *data = [[pipe fileHandleForReading] readDataToEndOfFile];
[task waitUntilExit];
[task release];
NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
BOOL processIsRunning = [result length] > 0;

Метод 3 также использует NSTask с опцией оболочки -c, но в этом случае выполняемая команда - это другая оболочка с собственной опцией -c (это был единственный способ, который я мог найти после долгих проб и ошибок) для включения конструкции if в команду, которая должна быть выполнена, конечно, это способ перебор для текущей проблемы):

NSTask *task = [[NSTask alloc] init];
[task setLaunchPath:@"/bin/sh"];
[task setArguments:[NSArray arrayWithObjects:@"-c",@"/bin/sh -c 'if [ \"$(ps -Ac | egrep -o 'ProcessName')\" = \"ProcessName\" ]; then echo 1; else echo 0; fi;'",nil]];
NSPipe *pipe = [NSPipe pipe];
[task setStandardOutput:pipe];
[task launch];
NSData *data = [[pipe fileHandleForReading] readDataToEndOfFile];
[task waitUntilExit];
[task release];
NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
BOOL processIsRunning = [result intValue] == 1;

Спасибо всем за прекрасную помощь.

0 голосов
/ 16 ноября 2011

Вот общий ответ, вообще не связанный с Какао:

Если вы хотите получить результат от system(), не используйте system(), используйте popen().

...