Hugh To
Hugh To

Reputation: 27

Python - subprocess.check_call gives a CalledProcessError exception

I want to call a subprocess to backup mysql database. A command line which ran fine in the terminal (and created a file named mydatabase.sql) is:

    mysqldump -uroot -ppassword --add-drop-database --database mydatabase > mydatabase.sql

Now the code to be ran by python to call a subprocess:

    args = shlex.split('mysqldump -uroot -ppassword --add-drop-database --database mydatabase > mydatabase.sql')
    subprocess.check_call(args)

The exeption is raised (no file created):

    Traceback (most recent call last):
      File "<pyshell#29>", line 1, in <module>
        subprocess.check_call(args)
      File "/usr/lib/python3.2/subprocess.py", line 485, in check_call
        raise CalledProcessError(retcode, cmd)
    subprocess.CalledProcessError: Command '['mysqldump', >'-uroot', '-ppassword', '--add-drop-database', '--database', >'mydatabase', '>', 'mydatabase.sql']' returned non-zero exit status 2

I have tried different ways, but they still don't work:

    args = shlex.split('/opt/lampp/bin/mysqldump -uroot -ppassword --add-drop-database --database mydatabase > mydatabase.sql')
    subprocess.check_call(args)

or

    args = shlex.split('/opt/lampp/bin/mysqldump -uroot -ppassword --add-drop-database --database mydatabase > mydatabase.sql')
    subprocess.Popen(args)

I also tried with shell=True or or shell=False. In both cases, they still don't work.

I have read the docs, google for the answer for my problem, but I haven't got a clue how to show my problem. stackoverflow is probably my last hope.

Upvotes: 1

Views: 3757

Answers (2)

mata
mata

Reputation: 69042

the problem here is the way you're redirecting the output.

  • if you pass the command as a list of arguments, then ">" will always be interpreted as a literal >, no matter if you use shell=True or shell=False
  • if you pass the command as a single string, then it hould work, but only if you have shell=True.
  • the best way do do what you want would be to redirect the output to a file directly from python:

    args = shlex.split('/opt/lampp/bin/mysqldump -uroot -ppassword --add-drop-database --database mydatabase')
    output = open("mydatabase.sql", "w")
    subprocess.Popen(args, stdout=output)
    

Upvotes: 2

mgilson
mgilson

Reputation: 309929

The problem may be the shell redirection. If you run with shell=True don't use shlex.split. In other words, try:

args = '/opt/lampp/bin/mysqldump -uroot -ppassword --add-drop-database --database mydatabase > mydatabase.sql'
subprocess.Popen(args,shell=True)

Of course, the safer solution would be to remove the shell redirection, use shlex.split on the arguments (without shell=True), and use subprocess.PIPE to capture the output (which you can then send to a file or do whatever you want with in your program)

For example:

args = '/opt/lampp/bin/mysqldump -uroot -ppassword --add-drop-database --database mydatabase'
p=psubprocess.Popen(shlex.split(args),shell=False,stdout=subprocess.PIPE)
p.wait()
returnvalue=p.returncode
data=p.stdout.read()
with open('mydatabase.sql','w') as f:
   f.write(data)

...

If you don't want to do anything with the data in your program, you can do the redirection a little more easily as described by mata.

Upvotes: 1

Related Questions