How do I capture a list of all running processes f

2020-07-14 06:09发布

I am wanting to capture a list of all running processes for OSX and save them as a file in Xcode / Cocoa. I googled this and all I found was:

[myWorkspace runningApplications];

And I am not sure how to do this. Please Help! Thank you!

2条回答
够拽才男人
2楼-- · 2020-07-14 06:45

yip to get high-level query the workspace as shown by abarnet to get 'all' processes go lower-level and execute ps via an NSTask and read the response via a NSPipe.

there's sample code by apple .. or use DDTask (a wrapper I wrote) github repository

NSString *exe = @"/bin/ps";
NSArray *args = @[@"-ax"];
NSString *res = [DDTask runTaskWithToolPath:exe andArguments:args andErrorHandler:nil];

[res writeToFile:@"./appslist" 
      atomically:YES
        encoding:NSUTF8StringEncoding
           error:NULL];
查看更多
够拽才男人
3楼-- · 2020-07-14 06:47

As explained in QA1123, "process" means multiple different things on a Mac (and that changes over time).

A "process" at the level of Cocoa (or Carbon, or once upon a time Classic) is basically what an end-user thinks of as a process: an app, fba, launchitem, etc. A "process" at the level of BSD is what a Unix-trained sysadmin thinks of as a process: something that shows up in ps. A high-level process can have multiple BSD processes; the other way around used to be possible too (under Classic); you can also have BSD processes that have no high-level process; etc.

If you want the high-level definition, forget that QA, the method -[NSWorkspace runningApplications] that you mentioned returns exactly what you want: an array with an object for each such app, and those objects have all the info you want. How you save them in a file depends on what information you want about each one, what format you want to save that information in, etc. Here's a complete sample app that will save the URL of each app, one per line, to a file called "./appslist":

#include <Cocoa/Cocoa.h>

int main(int argc, char *argv[]) {
  NSString *output = [NSString string];
  for (NSRunningApplication *app in 
       [[NSWorkspace sharedWorkspace] runningApplications]) {
    output = [output stringByAppendingFormat:@"%@\n",
                     [[app bundleURL] absoluteString]];
  }
  [output writeToFile:@"./appslist" 
           atomically:YES
             encoding:NSUTF8StringEncoding
                error:NULL];
  return 0;
}

If you want the low-level definition, the code in that QA is still accurate. Or you could just exec (or system or NSTask) ps.

Anyway, here's a sample that (with the code from that QA) prints the pid of each running process to a local file called "./bsdlist":

int main(int argc, char *argv[]) {
  kinfo_proc *procs;
  size_t count;
  int err = GetBSDProcessList(&procs, &count);
  if (err) return err;
  FILE *f = fopen("./bsdlist", "w");
  for (size_t i=0; i!=count; ++i) {
    fprintf(f, "%d\n", procs[i].kp_proc.p_pid);
  }
  fclose(f);
  free(procs);
}

If you like the idea of scripting ps, as mentioned above, there are a number of ways to do this.

The DDTask library mentioned in Dominik's answer looks like the easiest way to do this. If you want to use NSTask directly, it takes a bit more code to set up an NSPipe for stdout, etc. There's a good general CocoaDev (it's scripting ls rather than ps, but the ideas are all the same.)

Or you could drop down to a lower level. You could explicitly fork/exec and pass the results through stdout, but the popen function is designed to wrap all of that up, and it's a lot easier to use. The GNU C Programming Tutorial shows how to popen ps -A and pipe it to grep init; the first half of this is all you need.

Whichever way you go, the problem is that you're going to get back a mess of strings you have to parse. The best thing to do is pass different flags to ps to only get what you actually want. If all you want is the command lines, ps -ax -ocommand= will give you nothing but that, one command line per line—no header line to skip, no columns to parse apart, etc.

If you're worried about efficiency: The QA says "exec'ing ps will require parsing the tool's output and will not use system resources as efficiently as Listing 1." And this is true; formatting the sysctl output into strings just to pass them over a pipe and parse them again is extra work that has to take some CPU time. But unless you're doing this millions of times, I doubt it uses enough to make a difference. The best approach (to this, and most cases) is to write the simpler code first and test whether it's fast enough; if it is, you're done.

查看更多
登录 后发表回答