1

I'm trying to run ffmpeg on all the WAV files in a directory to convert them to mp3. This command works fine when I run it from the command-line, on my Fedora Linux machine:

/usr/bin/ffmpeg -i "Name With Spaces.wav" Name_With_Spaces.mp3

where Name With Spaces.wav is a file in the current directory. However, in Python 3.2 running in the same directory:

import os
files = os.listdir()
os.execl('/usr/bin/ffmpeg', '-i \"' + files[0] + '\"', files[0][:-4].replace(' ', '_') + '.mp3')

gives me the error (from ffmpeg): At least one input file must be specified. I don't see why this isn't working, because '-i \"' + files[0] + '\"' evaluates to -i "Name With Spaces.wav" and files[0][:-4].replace(' ', '_') + '.mp3' evaluates to Name_With_Spaces.mp3.

I've tried escaping spaces, using different quotation marks, using the full path (like /home/.../music/Name\ With\ Spaces.wav), and actually replacing the arguments with the real text, but nothing works. How can I get this to work?

2
  • Does it work for filenames without spaces? Commented Mar 24, 2016 at 13:55
  • @Fishstick No, it doesn't Commented Mar 24, 2016 at 13:59

2 Answers 2

2

If you want to use the os.execl method you have to modify your syntax a bit and -i must go as a different item in the list

import os
files = os.listdir()
# Separated the args to make it clear
args = '/usr/bin/ffmpeg', '-i', files[0], files[0][:-4].replace(' ', '_') + '.mp3'
# Yes, the binary appears twice
os.execl('/usr/bin/ffmpeg', *args)

The various exec* functions take a list of arguments for the new program loaded into the process. In each case, the first of these arguments is passed to the new program as its own name rather than as an argument a user may have typed on a command line. For the C programmer, this is the argv[0] passed to a program’s main(). For example, os.execv('/bin/echo', ['foo', 'bar']) will only print bar on standard output; foo will seem to be ignored.

Source https://docs.python.org/2/library/os.html#process-management

Sign up to request clarification or add additional context in comments.

4 Comments

OK, this also works, but the double binary is a little counter-intuitive. Could you explain why it has to be that way?
There is more information in the doc but I dont know if you have coded shell scripts in python, C, etc but execl works exactly like an Unix-like method so basically the first argument is always the program itself.
I will update the answer with the doc ref regarding to that
As the doc says, your first parameter -i which is the arg[0] was being ignored because it should be your program's name in this case ffmpeg. Then ffmpeg was complaining because you werent providing an input.
-1

I think it has something to do with how os.execl is reading the input that you are sending it. From the docs, it is interpreting each argument it gets as a separate argument, rather than a group of arguments. So it is internally doing something more clever than " ".join() the arguments you are giving to it. It is probably escaping any spaces you have outside quotation marks in each of the arguments you are sending.

One way to fix it would be to split up the "-i" part of the argument from the rest of the parameter:

os.execl('/usr/bin/ffmpeg', '-i', \"' + files[0] + '\", files[0][:-4].replace(' ', '_') + '.mp3')

For sanity, if you do the same code using os.system, it should work:

os.system(" ".join(['/usr/bin/ffmpeg', '-i \"' + files[0] + '\"', files[0][:-4].replace(' ', '_') + '.mp3']))

Alternatively, you can use subprocess:

import subprocess
subprocess.call(['/usr/bin/ffmpeg', '-i', \"' + files[0] + '\", files[0][:-4].replace(' ', '_') + '.mp3'])

2 Comments

I think you're missing a ) at the end in the os.system call, but with that, it works. Thanks! The subprocess solution is not working, it gives an error (again from ffmpeg) because it doesn't understand the -i option.
Edited my response - does that help?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.