[ACCEPTED]-Python module to shellquote/unshellquote?-quoting

Accepted answer
Score: 32

Looks like

try:  # py3
    from shlex import quote
except ImportError:  # py2
    from pipes import quote

quote("hello stack overflow's quite cool")
>>> '"hello stack overflow\'s quite cool"'

gets me far enough.

0

Score: 10

pipes.quote is now shlex.quote in python 3. It is easy enough 2 to use that piece of code.

https://github.com/python/cpython/blob/master/Lib/shlex.py#L281

That version handles 1 zero-length argument correctly.

Score: 8

To unquote, try shlex.split()

0

Score: 7

I'm pretty sure that pipes.quote is broken, and 3 should not be used, because it does not 2 handle zero-length arguments correctly:

>>> from pipes import quote
>>> args = ['arg1', '', 'arg3']
>>> print 'mycommand %s' % (' '.join(quote(arg) for arg in args))
mycommand arg1  arg3

I 1 believe the result should be something like

mycommand arg1 '' arg3
Score: 6

For shell quoting, this works: I've rigorously 4 tested it on Posix. [I'm assuming that 3 the list2cmdline function supplied by Python works as 2 advertised on Windows]

# shell.py
import os
if os.name == 'nt':
    from subprocess import list2cmdline

    def quote(arg):
        return list2cmdline([arg])[0]
else:
    import re
    _quote_pos = re.compile('(?=[^-0-9a-zA-Z_./\n])')

    def quote(arg):
        r"""
        >>> quote('\t')
        '\\\t'
        >>> quote('foo bar')
        'foo\\ bar'
        """
        # This is the logic emacs uses
        if arg:
            return _quote_pos.sub('\\\\', arg).replace('\n',"'\n'")
        else:
            return "''"

    def list2cmdline(args):
        return ' '.join([ quote(a) for a in args ])

The tests are here, if 1 anyone cares.

Score: 2

The standard library module subprocess has 4 the list2cmdline function which does this, albeit 3 according to Microsoft rules so I am not sure how reliable 2 it works in Unix-like environments for more 1 complicated command lines.

Score: 2

The quotefunction is available for quite some 4 time (Python 2.7?) -- the major drawback 3 is it moved from pipe module to shlex between 3.2 2 and 3.3.

You have to be prepared to handle 1 both cases while importing that function:

try:
    from shlex import quote
except ImportError:
    from pipes import quote
Score: 0

You should never have to shell quote. The 6 correct way to do a command is to not do 5 shell quoting and instead use subprocess.call or subprocess.Popen, and 4 pass a list of unquoted arguments. This 3 is immune to shell expansion.

i.e.

subprocess.Popen(['echo', '"', '$foo'], shell=False)

If you 2 want to unquote shell quoted data, you can 1 use shlex.shlex like this:

list(shlex.shlex("hello stack 'overflow'\''s' quite cool"))

More Related questions