0

I'm trying to process an input string in a Python script which is taken as a command line argument. This input might contain quotes as well (both single and double is possible) and I'm not able to provide it as input. I tried escaping it (with \), does not work.

Here are the details:

python3 code.py --foo="foo"  //works
python3 code.py --foo='foo'  //works
python3 code.py --foo='f"o"o'  //works
python3 code.py --foo="fo'o'"  //works
python3 code.py --foo="fo\"o"  //does not work
python3 code.py --foo='fo\'o'  //does not work

For my use case, there could also be a mixture of single or double quotes as well. Is there a workaround?

If it matters, here is the relevant code:

import argparse

parser = argparse.ArgumentParser(description="Demo")
parser.add_argument("--foo", required=True)
args = parser.parse_args()
print(args.foo)

Here is what happens when I try and run using input that "does not work":

$ python3 code.py --foo='v\'1'
> ^C

I get a "prompt", which I then exit by ctrl-C. Basically, \ does not escape the (middle) quote, and bash identifies my command as incomplete.

vish4071
  • 5,135
  • 4
  • 35
  • 65
  • windows or unix? – Bharel Jan 21 '22 at 10:35
  • Linux, ubuntu-20.04 to be exact. – vish4071 Jan 21 '22 at 10:45
  • It's not clear what you mean by "does not work" in the `"fo\"o"` case; it should result in `fo"o` being passed in. – tripleee Jan 21 '22 at 11:03
  • Single quotes are completely verbatim; backslash is just a regular character inside single quotes, like everything else except another single quote which always terminates the single-quoted string. – tripleee Jan 21 '22 at 11:04
  • That's the canonical, though there are several other common FAQs around this; perhaps see the [Stack Overflow `bash` tag info page](/tags/bash/info) which has a curated list which includes several. (Many Bash answers are also valid for `sh`, and obviously vice versa. If you are on Ubuntu, you are probably actually using Bash, not `sh`.) – tripleee Jan 21 '22 at 11:05
  • @tripleee My input can contain spaces and spl chars, so I need to wrap them around quotes. But these quotes could be part of string itself and I don't know how to pass those. – vish4071 Jan 21 '22 at 11:16
  • No no no no...there is a little miscommunication here. Would you please just copy and try my code on your system (if possible). You will know what I mean by "does not work". I'll try and edit the question in the meantime, @tripleee – vish4071 Jan 21 '22 at 11:20
  • 1
    All of your examples behave exactly as I expect. It was only two minutes of my life, but still, I will never get them back. Again, the problem seems to be purely that you expect something different than you should. The existing FAQs about how shell quoting works are the solution. The second to last example which you mark as "does not work" produces `fo"o` as predicted. – tripleee Jan 21 '22 at 11:26
  • 1
    @Bharel Reopening a question where you have posted an answer is somewhat dubious. Several commenters here have agreed that this is a basic FAQ about shell quoting, and should be closed as a duplicate. – tripleee Jan 21 '22 at 13:07
  • @tripleee sorry, I literally just received the privilege and didn't expect it'll single-handedly reopen, wanted to vote for reopening as it wasn't the same question. I'd appreciate it if you'd close back. – Bharel Jan 21 '22 at 13:12
  • 1
    @tripleee closed. I still think there should be a better duplicate target though, something along the lines of generally escaping a shell argument. – Bharel Jan 21 '22 at 13:21
  • https://unix.stackexchange.com/questions/456894/passing-an-argument-with-double-and-single-quotes-to-another-call-in-bash is perhaps useful as a cross-site duplicate but I feel that the answers to the two duplicates already cover the ground adequately. (Finding more duplicates is tricky because there is an imperial puckeyload of questions where the OP _thought_ they needed nested quoting where in fact they didn't.) – tripleee Jan 21 '22 at 13:40

1 Answers1

1

In a unix shell, to easily figure out the exact string you need to send to any commandline argument, you can use Python's shlex.quote():

>>> import shlex
>>> arg = r'''"fo\"o"'''
>>> print(shlex.quote(arg))
'"fo\"o"'

Make sure you wrap the argument with r and triple quotes.

If you happen to have triple quotes in your string, you'll have to manually escape everything without using r.

Bharel
  • 23,672
  • 5
  • 40
  • 80
  • I don't understand how this is relevant to my use case. Please elaborate....I just want to pass a generic string as a command line arg to a script and that string contains spaces, spl chars, quotes, etc. – vish4071 Jan 21 '22 at 11:27
  • 2
    This shows you exactly how to escape the string you want to pass to Python from the shell. – tripleee Jan 21 '22 at 11:29