Reputation: 165
i've got a script, that contains a list - the list is just some args that I want to pass to subprocess.run
like this
commands = ["bash command 1", "bash command 2",..]
here is my code
commands = ["bash command 1", "bash command 2",..]
process = subprocess.run([commands], stdout = subprocess.PIPE, shell = True)
how can I pass a list to my subprocess.run?
this is the Traceback
Traceback (most recent call last):
File "./retesting.py", line 18, in <module>
process = subprocess.run([commands], stdout = subprocess.PIPE, shell = True)
File "/usr/lib/python3.5/subprocess.py", line 383, in run
with Popen(*popenargs, **kwargs) as process:
File "/usr/lib/python3.5/subprocess.py", line 676, in __init__
restore_signals, start_new_session)
File "/usr/lib/python3.5/subprocess.py", line 1221, in _execute_child
restore_signals, start_new_session, preexec_fn)
TypeError: Can't convert 'list' object to str implicitly
I Have no idea what I'm doing wrong and I tried all sorts of things, so I'd appreciate really any help
Upvotes: 5
Views: 15993
Reputation: 2479
Before using shell=True
you have to understand what it does. Take the documentation for Popen
. It states:
The
shell
argument (which defaults toFalse
) specifies whether to use the shell as the program to execute. If shell isTrue
, it is recommended to pass args as a string rather than as a sequence.On Unix with
shell=True
, the shell defaults to/bin/sh
. Ifargs
is a string, the string specifies the command to execute through the shell. This means that the string must be formatted exactly as it would be when typed at the shell prompt. This includes, for example, quoting or backslash escaping filenames with spaces in them. Ifargs
is a sequence, the first item specifies the command string, and any additional items will be treated as additional arguments to the shell itself. That is to say,Popen
does the equivalent of:Popen(['/bin/sh', '-c', args[0], args[1], ...])
On Windows with
shell=True
, theCOMSPEC
environment variable specifies the default shell. The only time you need to specifyshell=True
on Windows is when the command you wish to execute is built into the shell (e.g.dir
orcopy
). You do not needshell=True
to run a batch file or console-based executable.
There is no way to execute a sequence of commands in one go, what you are doing is executing the first command and all other commands as passed when spawning the shell as options to that shell.
You want to do this instead:
for command in commands:
subprocess.run(command, shell=True)
Alternatively: you want to execute the sequence of commands as a single script:
subprocess.run(';'.join(commands), shell=True)
This said: if the commands inside command are only executables you should really avoid using shell=True
and use shlex.split
to provide the parsed argument list. If you need to specify the directory where the command should be executed you can use the cwd
argument to Popen
(or any similar function).
In your case you want something like:
import os, subprocess
subprocess.run(['app', '--email', 'some-email', '--password', 'somepassword'], cwd=os.path.expanduser('~/app-cli'))
Upvotes: 10