1

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

顶部-stats“pid,命令”

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

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

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

1 回答 1

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 有四种不同的任务/进程/程序/应用程序概念,它们不是一对一对应的,如果你想编写两个使用不同概念的程序的混搭,那就很难了——例如,top在 BSD 中的交易进程,而 Activity Monitor 处理 OS X 应用程序。

如果你真正想要的是使用相同的列表top,它是开源的,所以你可以阅读它并做同样的事情。

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

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);
    }
  }
}

显然,在实际代码中,您将希望动态分配缓冲区,返回值而不是仅仅转储它们,获得的不仅仅是路径等。但这足以为您提供基本概念。(当您获取其他信息时,请注意,如果您要求任何结构,除非您有权查看该结构的每个成员,否则您将收到 EPERM 错误。所以,PROC_PIDTASKALLINFO如果您只想要PROC_PIDT_SHORTBSDINFO.


无论如何,由于此 API 处理 BSD 进程(和 Mach 任务),而不是应用程序,因此它不会直接帮助您获得NSBundle想要提供 Activity Monitor 样式的功能。

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

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],将结果存储在字典中,将包的可执行路径映射到包,并使用它来查找每个进程很简单,但它似乎只对当前用户拥有的应用程序有用(并且可能在当前会话)。另一方面,枚举系统上的所有捆绑包,或询问 Spotlight 或类似的可能太慢而无法即时执行,但如果您在第一次运行时缓存它们就会过时。


代替 的另一种选择libproc是使用libtop

不幸的是,Apple 没有提供它。他们确实一个libtop实现,他们将其用于他们的top工具,但它实际上嵌入在源代码中top,不能从外部获得。您可以找到源代码(在上面的链接中)并将其嵌入到您的程序中,就像top它本身一样。

或者,GNU 和 BSD 进程实用程序都有 Mac 端口(尽管知道哪个名称与 Homebrew/MacPorts/Google 搜索一起使用并不总是那么容易……),因此您可以构建其中一个并使用它。

但是,除非您尝试编写跨平台软件(或者已经知道如何为 linux 或 FreeBSD 或其他任何东西编写此代码),否则我认为这只会增加额外的复杂性。

于 2013-01-16T21:56:00.020 回答