How Can I Properly Quote Bash Commands In Python When Using `subprocess.check_output`?
Solution 1:
With /bin/sh
, time ls
runs the external program /usr/bin/time
(your path may vary), which then runs ls
and reports the timing information to its standard error.
With /bin/bash
, time
is a keyword which instructs the bash
shell itself to report timing information for the execution of ls
to standard error. As such, you need to redirect the standard error of the shell, not the command, to standard output so that check_output
can capture it. It's a little ugly, but
s.check_output('exec 2>&1; time ls >/dev/null 2>&1', executable='/bin/bash', shell=True)
should work. The exec 2>&1
is the part that lets check_output
capture anything. The redirections following ls
are there to remove the output of ls
from what is captured; you can delete them if you want the command output as well.
Solution 2:
The error is caused by the fact that you should not quote strings when proving a list as command line. In fact:
>>> s.check_output(['bash', '-c', "time ls"])
real0m0.002s
user0m0.000s
sys 0m0.000s
'some content produced by ls'
Doesn't raise any exception, while:
>>> s.check_output(['bash', '-c', "'time ls'"])
bash: time ls: comando non trovato
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.3/subprocess.py", line 586, in check_output
raise CalledProcessError(retcode, process.args, output=output)
subprocess.CalledProcessError: Command '['bash', '-c', "'time ls'"]' returned non-zero exitstatus127
Raises the exception you see. Note the line before the traceback:
bash: time ls: comando non trovato
Quoting the 'time ls'
made bash
search for the program time ls
instead of program time
to be run with ls
as argument.
Why quoting is not needed? Easy: the list of strings specifies how the command line should be splitted. Putting "time ls"
in a single element of the list already provides the "quoting" you want.
As to how to obtain the output you want, since bash
's time
outputs on stderr
, a solution is to redirect stderr
to stdout
(and remove ls
output).
>>> s.check_output(['bash', '-c', "time ls > /dev/null"], stderr=s.STDOUT)
'\nreal\t0m0.001s\nuser\t0m0.000s\nsys\t0m0.000s\n'
Post a Comment for "How Can I Properly Quote Bash Commands In Python When Using `subprocess.check_output`?"