Skip to content

Commit

Permalink
pythongh-120952: Add subprocess.shell() function
Browse files Browse the repository at this point in the history
  • Loading branch information
vstinner committed Jun 27, 2024
1 parent b7a95df commit 7d5ee7a
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 0 deletions.
15 changes: 15 additions & 0 deletions Doc/library/subprocess.rst
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,18 @@ underlying :class:`Popen` interface can be used directly.
*stdout* and *stderr* attributes added


.. function:: shell(cmd, **kwargs)

Run a shell command. Wait for command to complete, then return a
:class:`CompletedProcess` instance.

See the :func:`run` function documentation for optional parameters.

Read the `Security Considerations`_ section before using this function.

.. versionadded:: 3.14


.. _frequently-used-arguments:

Frequently Used Arguments
Expand Down Expand Up @@ -764,6 +776,9 @@ quoted appropriately to avoid
vulnerabilities. On :ref:`some platforms <shlex-quote-warning>`, it is possible
to use :func:`shlex.quote` for this escaping.

The functions :func:`shell()` and :func:`getstatusoutput()` always use
``shell=True``.

On Windows, batch files (:file:`*.bat` or :file:`*.cmd`) may be launched by the
operating system in a system shell regardless of the arguments passed to this
library. This could result in arguments being parsed according to shell rules,
Expand Down
8 changes: 8 additions & 0 deletions Doc/whatsnew/3.14.rst
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,14 @@ pathlib
another.
(Contributed by Barney Gale in :gh:`73991`.)

subprocess
----------

* Add :func:`subprocess.shell` function to run a shell command.
Read the :ref:`Security Considerations <subprocess-security>` section before
using this function.
(Contributed by Victor Stinner in :gh:`120952`.)

symtable
--------

Expand Down
13 changes: 13 additions & 0 deletions Lib/subprocess.py
Original file line number Diff line number Diff line change
Expand Up @@ -2221,3 +2221,16 @@ def kill(self):
"""Kill the process with SIGKILL
"""
self.send_signal(signal.SIGKILL)


def shell(cmd, **kwargs):
"""
Run a shell command.
Read the Security Considerations section of the documentation before using
this function.
"""
if not isinstance(cmd, (str, bytes)):
raise TypeError("cmd type must be str or bytes")

return run(cmd, shell=True, **kwargs)
19 changes: 19 additions & 0 deletions Lib/test/test_subprocess.py
Original file line number Diff line number Diff line change
Expand Up @@ -1824,6 +1824,25 @@ def test_encoding_warning(self):
self.assertTrue(lines[0].startswith(b"<string>:2: EncodingWarning: "))
self.assertTrue(lines[2].startswith(b"<string>:3: EncodingWarning: "))

def test_shell(self):
# Unicode command
proc = subprocess.shell("echo Python", stdout=subprocess.PIPE, text=True)
self.assertEqual(proc.returncode, 0)
self.assertEqual(proc.stdout.rstrip(), "Python")

# Bytes command
proc = subprocess.shell(b"echo Python", stdout=subprocess.PIPE, text=True)
self.assertEqual(proc.returncode, 0)
self.assertEqual(proc.stdout.rstrip(), "Python")

# cmd type must be str or bytes, not list
with self.assertRaises(TypeError):
subprocess.shell(["echo", "Python"])

# Passing shell=False is invalid
with self.assertRaises(TypeError):
subprocess.shell("echo Python", shell=False)


def _get_test_grp_name():
for name_group in ('staff', 'nogroup', 'grp', 'nobody', 'nfsnobody'):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Add :func:`subprocess.shell` function to run a shell command. Read the
:ref:`Security Considerations <subprocess-security>` section before using
this function. Patch by Victor Stinner.

0 comments on commit 7d5ee7a

Please sign in to comment.