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!
Launch Terminal (Finder > Applications > Utilities). When Terminal is running, type top and hit Return. This will pull up a list of all your currently running processes.
On your Mac, choose Apple menu > System Preferences, click Keyboard , then click Shortcuts. In the sidebar, click Services, then select items to make them available in the Services menu or deselect items to remove them. Items appear in an app's Services menu only if they're relevant to the app or task.
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];
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With