Mac OS X中的top命令被截断

时间:2013-01-16 21:37:29

标签: objective-c macos cocoa

我正在尝试使用MacOS X中的“top”命令来确定哪个应用正在使用这些资源。 当我这样做时:

top -stats“pid,command”

如果进程名称太长,命令列将被截断。

如果查看活动监视器,则会正确显示进程名称(使用全名)+图标。我的问题是:

  1. 如何获取完整的进程名称?
  2. 有时应用程序图标显示在进程名称旁边,无论如何使用objective-c做类似的事情?我应该只是导航到应用程序内容文件夹并获取icns图像吗?

1 个答案:

答案 0 :(得分:5)

首先,如果您尝试以编程方式获取数据,那么驾驶top几乎绝对不是您想要做的。

但是,要回答你的直接问题:

  

如何获取完整的进程名称?

无法控制命令的截断。您可以使用-ncols参数为非交互式输出设置输出的宽度,但如果需要,则不会阻止top截断。

  

有时应用程序图标显示在进程名称旁边,无论如何使用objective-c进行类似的操作?我应该只是导航到应用程序内容文件夹并获取icns图像吗?

没有。您将如何处理具有多个.icns文件的应用程序,例如,用于文档图标? (例如,尝试使用iTunes。如果您选择第一个.icns,则会获得AIFF文档图标;如果选择最后一个,则会获得内部使用的最近电视节目图标。)

正确的方法是获取应用程序的NSBundle,然后执行以下操作:

NSString *iconFile = [bundle objectForInfoDictionaryKey:@"CFBundleIconFile"];
if (iconFile) {
    NSString *iconPath = [bundle pathForResource:iconFile ofType:@"icns"];
    // load and display the icon
}

那么,如果不是通过驾驶top,你实际想要怎么做呢?

嗯,你所要求的实际上并不是一个定义明确的事情。 OS X有四种不同的任务/进程/程序/应用程序概念,它们不一一对应,如果你想编写两个使用不同概念的程序的混搭,那就会让生活变得困难 - 例如{{1处理BSD进程,而Activity Monitor处理OS X应用程序。

如果你真正想要的是同一个top使用的列表,那么它就是开源的,所以你可以read it做同样的事情。

但获取BSD进程列表的最简单方法可能是top中的接口,特别是libproc.hproc_listallpids。例如:

proc_pidinfo

显然,在实际代码中,您将要动态分配缓冲区,返回值而不是仅仅转储它们,获取的不仅仅是路径等等。但这足以为您提供基本的想法。 (当你去获取更多信息时,请注意,如果你要求任何结构,除非你有权查看该结构的每个成员,否则你将收到一个EPERM错误。所以,不要去问{{1}如果你只想要int dump_proc_names() { int buf[16384]; int count = proc_listallpids(&buf, 16384*sizeof(int)); for (int i = 0; i != count; ++i) { int pid = buf[i]; char path[MAXPATHLEN+1] = {0}; int ret = proc_pidinfo(pid, PROC_PIDPATHINFO, 0, &path, sizeof(path)); if (ret < 0) { printf("%d: error %s (%d)\n", pid, strerror(errno), errno); } else { printf("%d: %s\n", pid, path); } } }


无论如何,由于这个API处理BSD进程(和Mach任务),而不是应用程序,它不会直接帮助你获得想要提供Activity Monitor风格功能的PROC_PIDTASKALLINFO

没有办法做到这一点完全正确,但你可能会逃避这样的事情:

PROC_PIDT_SHORTBSDINFO

可能有其他方法可以做到这一点,每种方法都有不同的权衡。例如,使用NSBundle,将结果存储在将捆绑包可执行路径映射到捆绑包的字典中,并使用它来查找每个流程很简单,但它似乎只对当前用户拥有的应用程序有用(可能在本届会议上)。另一方面,枚举系统上的所有软件包,或者询问Spotlight或类似软件可能会在运行时太慢,但如果你在第一次运行时缓存它们就会过时。


替代NSString *path = processPath; while (path && ![path isEqualTo:@"/"]) { NSBundle *bundle = [NSBundle bundleWithPath:path]; if (bundle) { if ([bundle executablePath != processPath]) return nil; return bundle; } path = [path stringByDeletingLastPathComponent]; } 的另一个选择是使用-[NSWorkspace runningApplications]

不幸的是,Apple没有提供它。他们拥有 libproc实现,用于libtop工具,但它实际上嵌入到libtop的源代码中,而不是从外部提供。您可以找到源代码(在上面的链接中)并将其嵌入到您的程序中,方式与top本身相同。

或者,GNU和BSD流程实用程序都有Mac端口(虽然知道在Homebrew / MacPorts / Google搜索中使用哪个名称并不总是那么简单......),所以你可以构建其中一个并使用它。

然而,除非你正在尝试编写跨平台软件(或者已经知道如何为linux或FreeBSD编写这些代码),我认为这只会增加额外的复杂性。