用|执行shell命令 (管道)使用NSTask

ed1*_*d1t 9 cocoa objective-c

我正在尝试ps -ef | grep test使用NSTask 执行此comamnd但我无法获取| grep test包含在NSTask中:

这就是我目前用来将ps -ef的输出变成字符串然后我需要以某种方式得到进程测试的pid

NSTask *task;
task = [[NSTask alloc] init];
[task setLaunchPath: @"/bin/ps"];

NSArray *arguments;
arguments = [NSArray arrayWithObjects: @"-ef", nil];
[task setArguments: arguments];    
NSPipe *pipe;
pipe = [NSPipe pipe];
[task setStandardOutput: pipe];

NSFileHandle *file;
file = [pipe fileHandleForReading];

[task launch];

NSData *data;
data = [file readDataToEndOfFile];

NSString *string;
string = [[NSString alloc] initWithData: data
                               encoding: NSUTF8StringEncoding];
NSLog (@"got\n%@", string);
Run Code Online (Sandbox Code Playgroud)

Rav*_*mio 19

管道是由壳体提供的特征,例如/bin/sh.您可以尝试通过这样的shell启动命令:

/* ... */
[task setLaunchPath: @"/bin/sh"];
/* ... */
arguments = [NSArray arrayWithObjects: @"-c", @"ps -ef | grep test", nil];
Run Code Online (Sandbox Code Playgroud)

但是,如果你让用户提供一个值(而不是硬编码test),那么你就会使程序容易受到shell注入攻击,这有点像SQL注入.另一个没有遇到此问题的方法是使用管道对象将标准输出ps与标准输入连接grep:

NSTask *psTask = [[NSTask alloc] init];
NSTask *grepTask = [[NSTask alloc] init];

[psTask setLaunchPath: @"/bin/ps"];
[grepTask setLaunchPath: @"/bin/grep"];

[psTask setArguments: [NSArray arrayWithObjects: @"-ef", nil]];
[grepTask setArguments: [NSArray arrayWithObjects: @"test", nil]];

/* ps ==> grep */
NSPipe *pipeBetween = [NSPipe pipe];
[psTask setStandardOutput: pipeBetween];
[grepTask setStandardInput: pipeBetween];

/* grep ==> me */
NSPipe *pipeToMe = [NSPipe pipe];
[grepTask setStandardOutput: pipeToMe];

NSFileHandle *grepOutput = [pipeToMe fileHandleForReading];

[psTask launch];
[grepTask launch];

NSData *data = [grepOutput readDataToEndOfFile];

/* etc. */
Run Code Online (Sandbox Code Playgroud)

这使用内置的Foundation功能来执行shell遇到|角色时所执行的相同步骤.

最后,正如其他人所指出的,使用grep是过度的.只需将其添加到您的代码中:

NSArray *lines = [string componentsSeparatedByString:@"\n"];
NSArray *filteredLines = [lines filteredArrayUsingPredicate: [NSPredicate predicateWithFormat: @"SELF contains[c] 'test'"]];
Run Code Online (Sandbox Code Playgroud)


Fra*_*rew 0

您可能需要在启动任务之前调用 [task waitUntilExit],以便进程可以在您读取输出之前完成运行。