4

How do you escape arguments for shell commands in ObjectivesC?

The ruby library has Shellwords (shellescape for NSString, shelljoin for NSArray, I don't need shellsplit). And I really need an escaped string, I know about NSTask, I don't need to execute that command.

Abizern
  • 146,289
  • 39
  • 203
  • 257
tig
  • 25,841
  • 10
  • 64
  • 96

2 Answers2

4

Escaping content for the shell is pretty easy if you use single quotes. The important thing to understand about shell quoting is that you can concatenate strings with different quoting styles, and even unquoted strings, in the same argument. For example, 'one two'three" four" mixes all 3 quoting styles, and ends up passing the string "one twothree four" as a single argument. The other thing to understand is that outside of quoting, you can backslash-escape special characters. The end result of this is a string like 'one two'\''three four' evaluates to the string "one two'three four", with the single quote. By using this trick, you can easily quote any string by replacing all single-quotes with the sequence '\'' and then wrapping the entire string in a single pair of single quotes.

If you have the following string:

I don't like shell quoting

and you apply this simple transformation you end up with

'I don'\''t like shell quoting'

and this gets evaluated back to the original string by the shell and handled as a single argument.

The following category on NSString should accomplish this transformation easily:

@implementation NSString (ShellQuoting)
// prefixed with "my", replace with your prefix of choice
- (NSString *)myStringByShellquotingString:(NSString *)str {
    NSMutableString *result = [NSMutableString stringWithString:str];
    [result replaceOccurrencesOfString:@"'" withString:@"'\\''" options:0 range:NSMakeRange(0, [result length])];
    [result insertString:@"'" atIndex:0];
    [result appendString:@"'"];
    return result;
}
@end
Lily Ballard
  • 182,031
  • 33
  • 381
  • 347
  • 1
    I thought about this way, but I don't like that all arguments will be in single quotes. Also shorter variant will be `[NSString stringWithFormat:@"'%@'", [string stringByReplacingOccurrencesOfString:@"'" withString:@"'\\''"]]` (also no mutable strings). The one way not to escape everyting is maybe to use NSCharacterSet with all chars that need to be escaped and do escaping only on match… – tig Jan 21 '11 at 04:48
  • i really like your answer, but it loses a lot of it's meaning, ironically, as you didn't ``back tick`` your examples, mid-paragraph, hence making it very hard to discern your intended "meaning". bash quoting is a freaky realm. it's like the force.. master it - and anything is possible. – Alex Gray Jan 16 '12 at 18:07
  • that's not a very good category, it's supposed to use self instead of passing in the string param. – malhal Nov 15 '12 at 00:13
  • @indiekiduk: Looking back at the code, I think I meant to make that a class method, not an instance method. – Lily Ballard Nov 15 '12 at 00:24
0

See the list of methods of NSString here. There are many obscure ones, but I don't think there's any that fits your job. You need to write one yourself.

If that method is called relatively infrequently, I would just call ruby binary from inside Objective-C and use shellescape, and then retrieve the result; it's stupid to re-invent the wheel.

Yuji
  • 34,103
  • 3
  • 70
  • 88