diff --git a/Lib/subprocess.py b/Lib/subprocess.py index 54c2eb515b60da..70bc8af4dcc0f1 100644 --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -618,7 +618,7 @@ def list2cmdline(seq): if result: result.append(' ') - needquote = (" " in arg) or ("\t" in arg) or not arg + needquote = not arg or not set(" \t&<>^|").isdisjoint(arg) if needquote: result.append('"') diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index ca35804fb36076..7b437e815538a4 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -3560,6 +3560,15 @@ def test_invalid_args(self): "import sys; sys.exit(47)"], preexec_fn=lambda: 1) + def test_args_quoting(self): + with tempfile.NamedTemporaryFile(suffix=".bat", delete_on_close=False) as f: + f.write(b"echo %*\n") + f.close() + p = subprocess.run([f.file.name, "a b", "", "c<>d", "e"], + capture_output=True) + self.assertEqual(p.returncode, 0, p.stderr) + self.assertEndsWith(p.stdout.strip(), b'"a b" "" "c<>d" e') + @support.cpython_only def test_issue31471(self): # There shouldn't be an assertion failure in Popen() in case the env diff --git a/Misc/NEWS.d/next/Windows/2025-05-22-16-36-52.gh-issue-133545.YHvz8H.rst b/Misc/NEWS.d/next/Windows/2025-05-22-16-36-52.gh-issue-133545.YHvz8H.rst new file mode 100644 index 00000000000000..e4668ed977c665 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2025-05-22-16-36-52.gh-issue-133545.YHvz8H.rst @@ -0,0 +1,2 @@ +In :mod:`subprocess` on Windows, in addition to space, tab, and empty string, quote arguments containing +``&<>^|``. Patch by John Keith Hohm.