Skip to content

Commit a5345e1

Browse files
authored
Merge pull request #3737 from Flamefire/run_cmd_shell
Eerror out when passing a list to run_cmd* to avoid running wrong command unintended, unless shell=True is used
2 parents b8f193c + 29c83d7 commit a5345e1

File tree

2 files changed

+18
-3
lines changed

2 files changed

+18
-3
lines changed

easybuild/tools/run.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ def get_output_from_process(proc, read_size=None, asynchronous=False):
128128

129129
@run_cmd_cache
130130
def run_cmd(cmd, log_ok=True, log_all=False, simple=False, inp=None, regexp=True, log_output=False, path=None,
131-
force_in_dry_run=False, verbose=True, shell=True, trace=True, stream_output=None, asynchronous=False):
131+
force_in_dry_run=False, verbose=True, shell=None, trace=True, stream_output=None, asynchronous=False):
132132
"""
133133
Run specified command (in a subshell)
134134
:param cmd: command to run
@@ -141,7 +141,7 @@ def run_cmd(cmd, log_ok=True, log_all=False, simple=False, inp=None, regexp=True
141141
:param path: path to execute the command in; current working directory is used if unspecified
142142
:param force_in_dry_run: force running the command during dry run
143143
:param verbose: include message on running the command in dry run output
144-
:param shell: allow commands to not run in a shell (especially useful for cmd lists)
144+
:param shell: allow commands to not run in a shell (especially useful for cmd lists), defaults to True
145145
:param trace: print command being executed as part of trace output
146146
:param stream_output: enable streaming command output to stdout
147147
:param asynchronous: run command asynchronously (returns subprocess.Popen instance if set to True)
@@ -155,6 +155,13 @@ def run_cmd(cmd, log_ok=True, log_all=False, simple=False, inp=None, regexp=True
155155
else:
156156
raise EasyBuildError("Unknown command type ('%s'): %s", type(cmd), cmd)
157157

158+
if shell is None:
159+
shell = True
160+
if isinstance(cmd, list):
161+
raise EasyBuildError("When passing cmd as a list then `shell` must be set explictely! "
162+
"Note that all elements of the list but the first are treated as arguments "
163+
"to the shell and NOT to the command to be executed!")
164+
158165
if log_output or (trace and build_option('trace')):
159166
# collect output of running command in temporary log file, if desired
160167
fd, cmd_log_fn = tempfile.mkstemp(suffix='.log', prefix='easybuild-run_cmd-')
@@ -318,6 +325,11 @@ def run_cmd_qa(cmd, qa, no_qa=None, log_ok=True, log_all=False, simple=False, re
318325
"""
319326
cwd = os.getcwd()
320327

328+
if not isinstance(cmd, string_type) and len(cmd) > 1:
329+
# We use shell=True and hence we should really pass the command as a string
330+
# When using a list then every element past the first is passed to the shell itself, not the command!
331+
raise EasyBuildError("The command passed must be a string!")
332+
321333
if log_all or (trace and build_option('trace')):
322334
# collect output of running command in temporary log file, if desired
323335
fd, cmd_log_fn = tempfile.mkstemp(suffix='.log', prefix='easybuild-run_cmd_qa-')

test/framework/run.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -524,7 +524,10 @@ def test_dry_run(self):
524524

525525
def test_run_cmd_list(self):
526526
"""Test run_cmd with command specified as a list rather than a string"""
527-
(out, ec) = run_cmd(['/bin/sh', '-c', "echo hello"], shell=False)
527+
cmd = ['/bin/sh', '-c', "echo hello"]
528+
self.assertErrorRegex(EasyBuildError, "When passing cmd as a list then `shell` must be set explictely!",
529+
run_cmd, cmd)
530+
(out, ec) = run_cmd(cmd, shell=False)
528531
self.assertEqual(out, "hello\n")
529532
# no reason echo hello could fail
530533
self.assertEqual(ec, 0)

0 commit comments

Comments
 (0)