mirror of https://github.com/python/cpython
bpo-22454: Add shlex.join() (the opposite of shlex.split()) (GH-7605)
This commit is contained in:
parent
f83d1dbd3b
commit
ca80495592
|
@ -37,6 +37,21 @@ The :mod:`shlex` module defines the following functions:
|
|||
standard input.
|
||||
|
||||
|
||||
.. function:: join(split_command)
|
||||
|
||||
Concatenate the tokens of the list *split_command* and return a string.
|
||||
This function is the inverse of :func:`split`.
|
||||
|
||||
>>> from shlex import join
|
||||
>>> print(join(['echo', '-n', 'Multiple words']))
|
||||
echo -n 'Multiple words'
|
||||
|
||||
The returned value is shell-escaped to protect against injection
|
||||
vulnerabilities (see :func:`quote`).
|
||||
|
||||
.. versionadded:: 3.8
|
||||
|
||||
|
||||
.. function:: quote(s)
|
||||
|
||||
Return a shell-escaped version of the string *s*. The returned value is a
|
||||
|
|
|
@ -552,6 +552,11 @@ convenience functions to automate the necessary tasks usually involved when
|
|||
creating a server socket, including accepting both IPv4 and IPv6 connections
|
||||
on the same socket. (Contributed by Giampaolo Rodola in :issue:`17561`.)
|
||||
|
||||
shlex
|
||||
----------
|
||||
|
||||
The new :func:`shlex.join` function acts as the inverse of :func:`shlex.split`.
|
||||
(Contributed by Bo Bayles in :issue:`32102`.)
|
||||
|
||||
shutil
|
||||
------
|
||||
|
|
|
@ -14,7 +14,7 @@ from collections import deque
|
|||
|
||||
from io import StringIO
|
||||
|
||||
__all__ = ["shlex", "split", "quote"]
|
||||
__all__ = ["shlex", "split", "quote", "join"]
|
||||
|
||||
class shlex:
|
||||
"A lexical analyzer class for simple shell-like syntaxes."
|
||||
|
@ -305,6 +305,11 @@ def split(s, comments=False, posix=True):
|
|||
return list(lex)
|
||||
|
||||
|
||||
def join(split_command):
|
||||
"""Return a shell-escaped string from *split_command*."""
|
||||
return ' '.join(quote(arg) for arg in split_command)
|
||||
|
||||
|
||||
_find_unsafe = re.compile(r'[^\w@%+=:,./-]', re.ASCII).search
|
||||
|
||||
def quote(s):
|
||||
|
|
|
@ -308,6 +308,26 @@ class ShlexTest(unittest.TestCase):
|
|||
self.assertEqual(shlex.quote("test%s'name'" % u),
|
||||
"'test%s'\"'\"'name'\"'\"''" % u)
|
||||
|
||||
def testJoin(self):
|
||||
for split_command, command in [
|
||||
(['a ', 'b'], "'a ' b"),
|
||||
(['a', ' b'], "a ' b'"),
|
||||
(['a', ' ', 'b'], "a ' ' b"),
|
||||
(['"a', 'b"'], '\'"a\' \'b"\''),
|
||||
]:
|
||||
with self.subTest(command=command):
|
||||
joined = shlex.join(split_command)
|
||||
self.assertEqual(joined, command)
|
||||
|
||||
def testJoinRoundtrip(self):
|
||||
all_data = self.data + self.posix_data
|
||||
for command, *split_command in all_data:
|
||||
with self.subTest(command=command):
|
||||
joined = shlex.join(split_command)
|
||||
resplit = shlex.split(joined)
|
||||
self.assertEqual(split_command, resplit)
|
||||
|
||||
|
||||
# Allow this test to be used with old shlex.py
|
||||
if not getattr(shlex, "split", None):
|
||||
for methname in dir(ShlexTest):
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
The :mod:`shlex` module now exposes :func:`shlex.join`, the inverse of
|
||||
:func:`shlex.split`. Patch by Bo Bayles.
|
Loading…
Reference in New Issue