2

I need to pass an '&' character to a script, running from Windows cmd.exe. Do you know how to escape it? Carets are used in cmd.exe for general escaping.

Trial 1

x:\abc>python args.py "hello world!" "" ^& end
args.py
hello world!

^&
end

Trial 2

x:\abc>python args.py "hello world!" "" "&" end
args.py
hello world!

^&
end

args.py

import sys
for i in sys.argv:
       print i

I have a C program: a.exe that is printing from argv, it seems to get the arguments correctly

With a.exe

x:\abc>a.exe "hello world!" "" "&" end
or
x:\abc>a.exe "hello world!" "" ^& end

produces

a.exe
hello world!

&
end

What's going on here, any ideas?

Robᵩ
  • 163,533
  • 20
  • 239
  • 308
nat.am
  • 31
  • 5
  • 1
    Notice the '^&' from args.py result, which is not happening with a.exe – nat.am Aug 08 '14 at 20:07
  • Try `import win32api; print win32api.GetCommandLine()`. – pts Aug 08 '14 at 20:07
  • I'm not worried about the script; trying to understand whether python interpreter is mucking with what I pass, and whether that is defined behavior. – nat.am Aug 08 '14 at 20:15
  • `sys.argv` is processed by the Python interpreter in a way which is possibly incompatible with `cmd.exe` escaping. `win32api.GetCommandLine()` isn't processed. – pts Aug 08 '14 at 20:23
  • OK, looking at trial 2 it is obvious that Python, for reasons of its own, is *adding* the caret. So it isn't an escaping issue per se, or anything to do with cmd.exe. An examination of the Python source code might help, if anybody is up for it. – Harry Johnston Aug 09 '14 at 00:25
  • What happens if you make a second script that calls the first with `subprocess.call` and provides the same arguments? – Kos Aug 10 '14 at 19:28
  • This question (http://stackoverflow.com/questions/6427732/how-can-i-escape-an-arbitrary-string-for-use-as-a-command-line-argument-in-windo) helped me come up with a solution. Also got to know that the above problem is **not specific** to python either. I have probably answered my own question. – nat.am Oct 14 '14 at 01:24

1 Answers1

1

I can't answer why Python on Windows is doing this, but this kind of issue ("this language, running on this platform, in these versions... does something wrong/different/weird") is pretty common.

A lot of my code that run across different language versions and platforms has at least a little "where am I running?" interrogation and a few shims to "make things right." Externalizing the handling of those special cases from your main logic helps to keep programs simple. So you might handle this problem with this kind of shim:

import platform
import sys

_WINDOWS = platform.system() == "Windows"

def strip_excess_caret(s):
    return s[1:] if s.startswith("^") else s

def clean_argv():
    if _WINDOWS:
        return [ strip_excess_caret(a) for a in sys.argv ]
    else:
        return sys.argv

for arg in clean_argv():
    print arg
Jonathan Eunice
  • 21,653
  • 6
  • 75
  • 77
  • this shim may not be needed after all.. check http://stackoverflow.com/questions/6427732/how-can-i-escape-an-arbitrary-string-for-use-as-a-command-line-argument-in-windo – nat.am Oct 14 '14 at 01:30
  • You mean using a more sophisticated/complete function to quote each command line argument? That is a quality solution for a given platform (like Windows), though Unix/Linux and other platforms probably need their own escape functions. Platform-dependent shim functions are still required, if only to choose the right escape function. And command line args not the only place where behavior differs platform to platform. – Jonathan Eunice Oct 14 '14 at 09:38
  • Yes, I was referring to windows only here, as I asked this question specifically for cmd.exe. But you are right about platform independent-ness for normal programs. – nat.am Oct 14 '14 at 22:54