如何从Objective-C Cocoa应用程序执行终端命令(如grep) ?
当前回答
in the spirit of sharing... this is a method I use frequently to run shell scripts. you can add a script to your product bundle (in the copy phase of the build) and then have the script be read and run at runtime. note: this code looks for the script in the privateFrameworks sub-path. warning: this could be a security risk for deployed products, but for our in-house development it is an easy way to customize simple things (like which host to rsync to...) without re-compiling the application, but just editing the shell script in the bundle.
//------------------------------------------------------
-(void) runScript:(NSString*)scriptName
{
NSTask *task;
task = [[NSTask alloc] init];
[task setLaunchPath: @"/bin/sh"];
NSArray *arguments;
NSString* newpath = [NSString stringWithFormat:@"%@/%@",[[NSBundle mainBundle] privateFrameworksPath], scriptName];
NSLog(@"shell script path: %@",newpath);
arguments = [NSArray arrayWithObjects:newpath, 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 (@"script returned:\n%@", string);
}
//------------------------------------------------------
编辑:包括修复NSLog问题
如果你正在使用NSTask通过bash运行命令行实用程序,那么你需要包括这条神奇的行来保持NSLog工作:
//The magic line that keeps your log where it belongs
[task setStandardInput:[NSPipe pipe]];
时代背景:
NSPipe *pipe;
pipe = [NSPipe pipe];
[task setStandardOutput: pipe];
//The magic line that keeps your log where it belongs
[task setStandardInput:[NSPipe pipe]];
解释在这里:http://www.cocoadev.com/index.pl?NSTask
其他回答
你可以使用NSTask。下面是一个运行'/usr/bin/grep foo bar.txt'的例子。
int pid = [[NSProcessInfo processInfo] processIdentifier];
NSPipe *pipe = [NSPipe pipe];
NSFileHandle *file = pipe.fileHandleForReading;
NSTask *task = [[NSTask alloc] init];
task.launchPath = @"/usr/bin/grep";
task.arguments = @[@"foo", @"bar.txt"];
task.standardOutput = pipe;
[task launch];
NSData *data = [file readDataToEndOfFile];
[file closeFile];
NSString *grepOutput = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
NSLog (@"grep returned:\n%@", grepOutput);
nspope和NSFileHandle用于重定向任务的标准输出。
有关在Objective-C应用程序中与操作系统交互的更详细信息,您可以查看Apple开发中心的这篇文档:与操作系统交互。
编辑:包括修复NSLog问题
如果你正在使用NSTask通过bash运行命令行实用程序,那么你需要包括这条神奇的行来保持NSLog工作:
//The magic line that keeps your log where it belongs
task.standardOutput = pipe;
解释在这里:https://web.archive.org/web/20141121094204/https://cocoadev.com/HowToPipeCommandsWithNSTask
还有一个很好的老式POSIX系统("echo -en '\007'");
肯特的文章给了我一个新想法。这个runCommand方法不需要脚本文件,只需要用一行来运行命令:
- (NSString *)runCommand:(NSString *)commandToRun
{
NSTask *task = [[NSTask alloc] init];
[task setLaunchPath:@"/bin/sh"];
NSArray *arguments = [NSArray arrayWithObjects:
@"-c" ,
[NSString stringWithFormat:@"%@", commandToRun],
nil];
NSLog(@"run command:%@", commandToRun);
[task setArguments:arguments];
NSPipe *pipe = [NSPipe pipe];
[task setStandardOutput:pipe];
NSFileHandle *file = [pipe fileHandleForReading];
[task launch];
NSData *data = [file readDataToEndOfFile];
NSString *output = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
return output;
}
你可以这样使用这个方法:
NSString *output = runCommand(@"ps -A | grep mysql");
Objective-C (Swift见下文)
清理顶部答案中的代码,使其更具可读性,减少冗余,增加单行方法的好处,并使其成为NSString类别
@interface NSString (ShellExecution)
- (NSString*)runAsCommand;
@end
实现:
@implementation NSString (ShellExecution)
- (NSString*)runAsCommand {
NSPipe* pipe = [NSPipe pipe];
NSTask* task = [[NSTask alloc] init];
[task setLaunchPath: @"/bin/sh"];
[task setArguments:@[@"-c", [NSString stringWithFormat:@"%@", self]]];
[task setStandardOutput:pipe];
NSFileHandle* file = [pipe fileHandleForReading];
[task launch];
return [[NSString alloc] initWithData:[file readDataToEndOfFile] encoding:NSUTF8StringEncoding];
}
@end
用法:
NSString* output = [@"echo hello" runAsCommand];
如果你在输出编码方面有问题:
// Had problems with `lsof` output and Japanese-named files, this fixed it
NSString* output = [@"export LANG=en_US.UTF-8;echo hello" runAsCommand];
希望它对你和未来的我一样有用。(嗨,你!)
斯威夫特4
下面是一个使用管道、进程和字符串的Swift示例
extension String {
func run() -> String? {
let pipe = Pipe()
let process = Process()
process.launchPath = "/bin/sh"
process.arguments = ["-c", self]
process.standardOutput = pipe
let fileHandle = pipe.fileHandleForReading
process.launch()
return String(data: fileHandle.readDataToEndOfFile(), encoding: .utf8)
}
}
用法:
let output = "echo hello".run()
in the spirit of sharing... this is a method I use frequently to run shell scripts. you can add a script to your product bundle (in the copy phase of the build) and then have the script be read and run at runtime. note: this code looks for the script in the privateFrameworks sub-path. warning: this could be a security risk for deployed products, but for our in-house development it is an easy way to customize simple things (like which host to rsync to...) without re-compiling the application, but just editing the shell script in the bundle.
//------------------------------------------------------
-(void) runScript:(NSString*)scriptName
{
NSTask *task;
task = [[NSTask alloc] init];
[task setLaunchPath: @"/bin/sh"];
NSArray *arguments;
NSString* newpath = [NSString stringWithFormat:@"%@/%@",[[NSBundle mainBundle] privateFrameworksPath], scriptName];
NSLog(@"shell script path: %@",newpath);
arguments = [NSArray arrayWithObjects:newpath, 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 (@"script returned:\n%@", string);
}
//------------------------------------------------------
编辑:包括修复NSLog问题
如果你正在使用NSTask通过bash运行命令行实用程序,那么你需要包括这条神奇的行来保持NSLog工作:
//The magic line that keeps your log where it belongs
[task setStandardInput:[NSPipe pipe]];
时代背景:
NSPipe *pipe;
pipe = [NSPipe pipe];
[task setStandardOutput: pipe];
//The magic line that keeps your log where it belongs
[task setStandardInput:[NSPipe pipe]];
解释在这里:http://www.cocoadev.com/index.pl?NSTask
推荐文章
- 是否有可能禁用浮动头在UITableView与UITableViewStylePlain?
- 从Cocoa应用程序执行一个终端命令
- Android Studio无法找到有效的Jvm(与MAC OS相关)
- Swift编译器错误:“框架模块内的非模块化头”
- 从父iOS访问容器视图控制器
- 自定义dealloc和ARC (Objective-C)
- 调整UITableView的大小以适应内容
- 在代码中为UIButton设置一个图像
- NSRange从Swift Range?
- UICollectionView中的单元格间距
- 如何在交互式Python中查看整个命令历史?
- 我如何在我的iOS应用程序中每n分钟得到一个后台位置更新?
- 如何使用UIVisualEffectView来模糊图像?
- 在OSX中永久设置PATH环境变量
- 如何停止mysqld