如何从shell命令捕获输出?

时间:2011-11-16 04:55:35

标签: cocoa shell capture

可可新手警告!

我发现以下shell命令是确定进程是否正在运行的好方法(1 =正在运行,0 =未运行):

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

我可以使用“system”命令将其合并到Cocoa中:

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

但是,输出被定向到运行日志,我无法弄清楚如何在我的Cocoa代码中捕获结果(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)的方式正确实现此shell命令? (我知道确定进程是否正在运行的其他方法,但我的问题的部分原因是为了学习如何在Cocoa中实现shell脚本。)

非常感谢您对此问题的任何帮助。

3 个答案:

答案 0 :(得分:3)

你做错了。不要问“如何运行外部进程来执行X”,而应该问“如何编写代码来执行X”。

您无需使用外部脚本来获取进程列表。通常,出于性能和安全原因,您应该始终尝试使用API​​而不是启动外部任务。

在这种情况下,您需要的API是sysctl C接口。

JongAm Park写了一个Objective-C wrapper来使用sysctl来获取正在运行的进程列表。他的帖子中的评论也有很好的观点。

或者,您可以通过查看the source code for the ps command.

了解Apple如何做到这一点

答案 1 :(得分:2)

Rob,感谢您尽可能在代码中使用直接解决方案的一般指针。我浏览了JongAm Park的sysctl包装器,以及Apple的ps源代码。合并需要一段时间,但我现在知道在哪里寻找获得流程列表的直接解决方案。

shellter和tripleee,感谢您关于与shell命令交互的建议。根据你的建议,我有三种工作方法(!):

方法1使用system命令的返回码(不需要egrep -o):

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

方法2使用NSTask和shell -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也使用带有-c选项的NSTask,但在这种情况下,要执行的命令是另一个具有自己的-c选项的shell(这是我之后找到的唯一方法)在要执行的命令中包含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;

谢谢大家的帮助。

答案 2 :(得分:0)

以下是一个不涉及Cocoa的一般答案:

如果您希望从system()获取输出,请不要使用system(),请使用popen()