views:

568

answers:

5

Here's a barebones Python app that simply prints the command-line arguments passed in:

import sys
if __name__ == "__main__":
    print "Arguments:"
    for i in range(len(sys.argv)):
        print "[%s] = %s" % (i, sys.argv[i])

And here's some sample runs:

python args.py hello world
Arguments:
[0] = args.py
[1] = hello
[2] = world

python args.py "hello world"
Arguments:
[0] = args.py
[1] = hello world

python args.py "hello\world"
Arguments:
[0] = args.py
[1] = hello\world

So far so good. But now when I end any argument with a backslash, Python chokes on it:

python args.py "hello\world\"
Arguments:
[0] = args.py
[1] = hello\world"

python args.py "hello\" world "any cpu"
Arguments:
[0] = args.py
[1] = hello" world any
[2] = cpu

I'm aware of Python's less-than-ideal raw string behavior via the "r" prefix (link), and it seems clear that it's applying the same behavior here.

But in this case, I don't have control of what arguments are passed to me, and I can't enforce that the arguments don't end in a backslash. How can I work around this frustrating limitation?

--

Edit: Thanks to those who pointed out that this behavior isn't specific to Python. It seems to be standard shell behavior (at least on Windows, I don't have a Mac at the moment).

Updated question: How can I accept args ending in a backslash? For example, one of the arguments to my app is a file path. I can't enforce that the client sends it to me without a trailing backslash, or with the backslash escaped. Is this possible in any way?

+1  A: 

The backslash (\) is escaping the ". That's all. That is how it is supposed to work.

voyager
+7  A: 

That's likely the shell treating \ as an escape character, and thus escaping the character. So the shell sends \" as " (because it thinks you are trying to escape the double quote). The solution is to escape the escape character, like so: $ python args.py "hello\world\\".

mipadi
Up. Plus, it is not python that chokes, its the command-line. Its waiting for the ending ", sinse you have escaped the " you taped.
Havenard
Alternatively, use single quotes: bash doesn't do escapes inside singly-quoted strings, so `$ python args.py 'hello world\'` behaves as expected.
Adam Rosenfield
Thanks mipadi. Btw, I noticed you only escaped the second backslash, but that seems to be correct.
Aseem Kishore
Adam, that's a brilliant tip (using single quotes instead of double). It works on Windows too. I'll keep that in mind for the future.
Aseem Kishore
@ Aseem: I just copied one of the examples you listed in the original post.
mipadi
OP says that he can't control the arguments passed to his program. So any answer that depends on changing the arguments isn't helpful.
Schof
+2  A: 

The backslash 'escapes' the character following it. This means that the closing quotation marks become a part of the argument, and don't actually terminate the string.

This is the behaviour of the shell you're using (presumably bash or similar), not Python (although you can escape characters within Python strings, too).

The solution is to escape the backslashes:

python args.py "hello\world\\"

Your Python script should then function as you expect it to.

harto
Well, the first backslash apparently isn't supposed to be escaped (see mipadi's post above, he doesn't escape the first one), but thanks for pointing out that it's not Python-specific.
Aseem Kishore
I suppose the first double-backslash isn't strictly required in this case, but that's only because `\w` doesn't mean anything to the shell. If the first slash were followed by an `n` or `t`, you'd end up with unwanted whitespace in the string. I'd just escape both slashes to be a little more defensive.
harto
No, I mean that it actually gives an incorrect input. python args.py "hello\\world\\" Arguments: [0] = args.py [1] = hello\\world\
Aseem Kishore
Ah, OK. My mistake.
harto
+1  A: 

If this is on Windows, then you are not using a standard Windows command prompt (or shell). This must be bash doing this. The Windows command prompt doesn't treat backslash as an escape character (since it's the file path separator).

Extra trivia point: the quoting character in Windows command prompts is caret: ^

Ned Batchelder
But it is on Windows. I'm seeing this behavior both with a Python console app and a C# .NET console app.
Aseem Kishore
But what shell are you using? You can use bash as your shell on Windows. I'm not saying it isn't happening, just wanted to clarify that your choice of shell matters.
Ned Batchelder
A: 

The Microsoft Parameter Parsing Rules

These are the rules for parsing a command line passed by CreateProcess() to a program written in C/C++:

  1. Parameters are always separated by a space or tab (multiple spaces/tabs OK)
  2. If the parameter does not contain any spaces, tabs, or double quotes, then all the characters in the parameter are accepted as is (there is no need to enclose the parameter in double quotes).
  3. Enclose spaces and tabs in a double quoted part
  4. A double quoted part can be anywhere within a parameter
  5. 2n backslashes followed by a " produce n backslashes + start/end double quoted part
  6. 2n+1 backslashes followed by a " produce n backslashes + a literal quotation mark
  7. n backslashes not followed by a quotation mark produce n backslashes
  8. If a closing " is followed immediately by another ", the 2nd " is accepted literally and added to the parameter (This is the undocumented rule.)

For a detailed and clear description see http://www.autohotkey.net/~deleyd/parameters/parameters.htm

Charlie36