如何从Objective-C Cocoa应用程序执行终端命令(如grep) ?
当前回答
还有一个很好的老式POSIX系统("echo -en '\007'");
其他回答
你可以使用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
肯特的文章给了我一个新想法。这个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()
或者因为Objective C只是C,上面有一些OO层,你可以使用posix对等物:
int execl(const char *path, const char *arg0, ..., const char *argn, (char *)0);
int execle(const char *path, const char *arg0, ..., const char *argn, (char *)0, char *const envp[]);
int execlp(const char *file, const char *arg0, ..., const char *argn, (char *)0);
int execlpe(const char *file, const char *arg0, ..., const char *argn, (char *)0, char *const envp[]);
int execv(const char *path, char *const argv[]);
int execve(const char *path, char *const argv[], char *const envp[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[], char *const envp[]);
它们包含在unistd.h头文件中。
fork, exec和wait应该有用,如果你不是在寻找Objective-C特定的方法。Fork创建当前运行程序的副本,exec用一个新程序替换当前运行的程序,然后wait等待子进程退出。例如(没有任何错误检查):
#include <stdlib.h>
#include <unistd.h>
pid_t p = fork();
if (p == 0) {
/* fork returns 0 in the child process. */
execl("/other/program/to/run", "/other/program/to/run", "foo", NULL);
} else {
/* fork returns the child's PID in the parent. */
int status;
wait(&status);
/* The child has exited, and status contains the way it exited. */
}
/* The child has run and exited by the time execution gets to here. */
还有一个系统,它运行命令,就像您从shell的命令行输入命令一样。这样更简单,但你对情况的控制力更弱。
我假设你正在使用一个Mac应用程序,所以这些链接指向苹果关于这些函数的文档,但它们都是POSIX,所以你应该在任何POSIX兼容的系统上使用它们。
推荐文章
- 是否有可能禁用浮动头在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