0

I'm writing a command line helper for one of my cocoa apps. This helper tool is supposed to execute an instance of shell ( /bin/sh ) using NSTask. As you all know it's possible to execute sh taking advantage of -c, you can pass one or more command as an argument to be executed.

For example running /bin/sh -c "networksetup -setwebproxystate Wi-Fi on"

executes networksetup -setwebproxystate Wi-Fi on .

Now, Here's the question :

When I set the launch path to sh ( [task setLaunchPath:@"/bin/sh"] ) , and then set Arguments as following :

cmd = "-c,\\\"networksetup\\_-setwebproxystate\\_Wi-Fi\\_on\\\"";
stringArguments = [NSMutableString stringWithFormat:@"%s", cmd.c_str()];
stringArguments = [[stringArguments stringByReplacingOccurrencesOfString:@"_" withString:@" "] mutableCopy];
arguments = [stringArguments componentsSeparatedByString:@","];        
[task setArguments:arguments];

I see that somehow -c argument is skipped, because I get the following error :

/bin/sh: "networksetup -setwebproxystate Wi-Fi on": command not found

and that's because "networksetup -setwebproxystate Wi-Fi on" is executed directly not as an argument after sh -c.

I know I couldn't explain in the clearest way possible, but hope I could deliver what I meant.

I tried almost everything came to my mind, but I'm stuck with this. Any suggestions is really appreciated.

Sepehrom
  • 1,335
  • 2
  • 16
  • 33

2 Answers2

2

The problem is in your amazingly convoluted way of specifying the command string. NSTask does not need quotes around the arguments. You are ending up with arguments containing this:

[0] ==> -c

[1] ==> "networksetup -setwebproxystate Wi-Fi on"

Note the double-quotes. Why not just use

 arguments = [NSArray arrayWithObjects:
    @"-c",
    @"networksetup -setwebproxystate Wi-Fi on",
    nil ];
Jeff Laing
  • 913
  • 7
  • 13
  • `NSTask` does not need double quotes, `sh -c` DOES NEED. I first had lots of problems to pass `"` in arguments because it was ignored when I was passing it like `\"`, But passing another `\\`` before solved it and now I'm dealing with this ! Try executing commands with `sh -c` and you will notice what I say. ( For one example you can combine commands like `sh -c "firstCommand && secondCommand" so existence of quotes is necessary ) ;) – Sepehrom Mar 09 '14 at 23:40
  • And by the way, the reason that I wrote `cmd = ...` like that is that, `cmd` is being set from a value that `cin>>` is receiving, so that's not as easy as it sounds to pass parameters :D – Sepehrom Mar 09 '14 at 23:44
  • No, Unkn0wn, 'sh -c' does *not* need double quote in and of itself. The command-line-processor that you are typing it into does. What 'sh -c' requires is a SINGLE ARGUMENT which is the entire command to be parsed and executed. If that command requires its own quotes, then fine. And I can't see why you need so many backslashes - I suspect you may be confusing what is displayed by your logging mechanism with what is actually in your variables... – Jeff Laing Mar 10 '14 at 11:30
1

When entering a command at the shell prompt double-quotes are used to pass a string as a single argument when it would otherwise be passed as multiple arguments. When using NSTask (or function/system calls in the exec family) you pass each argument individually, the shell does not need to parse a command line, and so double quotes are not required. The following fragment:

NSTask *task = [NSTask new];

[task setLaunchPath:@"/bin/sh"];

[task setArguments:@[@"-c", @"networksetup -setwebproxystate Wi-Fi on"]];

[task launch];

will do the task you want. The two arguments are passed using a literal array expression, each argument is just a string and may contain spaces etc.

HTH

CRD
  • 52,522
  • 5
  • 70
  • 86