1

Cocoa newbie warning!

I find the following shell command to be a nice way to determine if a process is running (1 = running, 0 = not running):

if [ $(ps -Ac | egrep -o 'ProcessName') ]; then echo 1; else echo 0; fi;

I can incorporate this into Cocoa with the "system" command:

system("if [ $(ps -Ac | egrep -o 'Finder') ]; then echo 1; else echo 0; fi;");

However, the output is directed to the run log, and I can't figure out how to capture the result (1 or 0) in my Cocoa code.

I tried implementing this with NSTask as follows:

NSTask *task = [[NSTask alloc] init];
[task setLaunchPath:@"/bin/sh"];
[task setArguments:[NSArray arrayWithObject:@"if [ $(ps -Ac | egrep -o 'Finder') ]; then echo 1; else echo 0; fi;"]];
NSPipe *pipe = [NSPipe pipe];
[task setStandardOutput:pipe];
[task launch];
NSData *data = [[pipe fileHandleForReading] readDataToEndOfFile];
[task waitUntilExit];
[task release];
NSString *output = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog (@"%@", output);
[output release];

However, this generates the following error message:

if [ $(ps -Ac | egrep -o 'Finder') ]; then echo 1; else echo 0; fi;: No such file or directory

Can you please tell me how I can correctly implement this shell command in a way that allows me to capture the output (1 or 0) in code? (I am aware of other methods of determining whether a process is running, but part of the reason for my question is to learn how to implement shell scripts in general within Cocoa.)

Thank you very much for any help with this problem.

4
  • 2
    to see how it works, why rely on a relatively complex expression for starters. See if you can get echo 1 to work. Also because of the ` No such file or directory` msg, that the system() called directly to the local dir, looking for a file name if .... I'm guess that you need to wrap your 'script' with the path to the shell AND -e (execute option?) of the shell, producing the simple case test [task setArguments:[NSArray arrayWithObject:@"/bin/bash -e 'echo 1'"]]. Why not just use your code to call scripts saved to your filesystem? Good luck. Commented Nov 16, 2011 at 5:30
  • 1
    Shell scripts are executed by the shell; to run a shell from system() you'd use something like system("sh -c 'echo moo'"). You are better off just capturing the result code from system() rather than the command's output, and then you don't need the if and the echos: system("sh -c 'ps -Ac | egrep -o Finder'") and the exit code from egrep will be returned, indicating whether or not there was a match. Commented Nov 16, 2011 at 6:08
  • 1
    There is no need to test the output of ps | egrep. Test the return value of egrep instead. IOW, just write "if ps -Ac | egrep -o 'Finder' > /dev/null" (or just use pgrep!) Commented Nov 16, 2011 at 13:38
  • William, thank you. I incorporated your suggestion in my working answer below. Commented Nov 16, 2011 at 15:11

3 Answers 3

3

You're doing it wrong. Rather than asking "how do I run an external process to do X" you should ask "how do I write code to do X".

You don't need to use an external script to get a list of processes. In general, you should always try to use an API rather than launch an external task, for both performance and security reasons.

In this case the API you want is the the sysctl C interface.

JongAm Park has written an Objective-C wrapper for using sysctl to get a list of running processes. There are good points made in the comments on his post also.

Alternatively, you can see how Apple does it by looking at the source code for the ps command.

Sign up to request clarification or add additional context in comments.

Comments

2

Rob, thank you for the general pointer about using a direct solution in code whenever possible. I looked through JongAm Park's wrapper for sysctl, as well as Apple's ps source code. It will take a while to incorporate, but I know now where to look for a direct solution to getting a list of processes.

shellter and tripleee, thank you for your suggestions concerning interacting with shell commands. Based on your suggestions, I got three methods to work (!):

Method 1 uses the system command's return code (no need for egrep -o):

BOOL processIsRunning = system("ps -Ac | grep 'ProcessName' > /dev/null") == 0;

Method 2 uses NSTask with the shell -c option (note -c rather than -e):

NSTask *task = [[NSTask alloc] init];
[task setLaunchPath:@"/bin/sh"];
[task setArguments:[NSArray arrayWithObjects:@"-c",@"ps -Ac | grep 'ProcessName'",nil]];
NSPipe *pipe = [NSPipe pipe];
[task setStandardOutput:pipe];
[task launch];
NSData *data = [[pipe fileHandleForReading] readDataToEndOfFile];
[task waitUntilExit];
[task release];
NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
BOOL processIsRunning = [result length] > 0;

Method 3 also uses NSTask with the shell -c option, but in this case, the command to be executed is another shell with its own -c option (this was the only way I could find after much trial and error to incorporate an if construct in the command to be executed; of course, it is way overkill for the current problem):

NSTask *task = [[NSTask alloc] init];
[task setLaunchPath:@"/bin/sh"];
[task setArguments:[NSArray arrayWithObjects:@"-c",@"/bin/sh -c 'if [ \"$(ps -Ac | egrep -o 'ProcessName')\" = \"ProcessName\" ]; then echo 1; else echo 0; fi;'",nil]];
NSPipe *pipe = [NSPipe pipe];
[task setStandardOutput:pipe];
[task launch];
NSData *data = [[pipe fileHandleForReading] readDataToEndOfFile];
[task waitUntilExit];
[task release];
NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
BOOL processIsRunning = [result intValue] == 1;

Thank you all for the wonderful help.

Comments

0

Here is a general answer not involving Cocoa at all:

If you want to get output from system(), don't use system(), use popen().

1 Comment

Thank you. I will look into popen(). So many ways to solve a problem!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.