Hello, newbie here to both this forum and Python, so expect silliness!

My first project has been to build a GUI front end for some command line utilities I use regularly. One of them is the utility: eac3to which joins mp3 files together. It's command line is: "eac3to.exe infile1+infile2+infile3 outfile"

Using loops I can successfully scan a directory and make a list of the mp3 files in it. From it generate exactly the command line I need and it works beautifully. Unless one of the mp3 files has an apostrophe in the file name, in which case Python changes it to ", this , of course, makes it impossible for the OS to find the file.

Obviously the quick fix is to rename my files, but I don't like to be beaten!
Please give me a clue. Thanks.

Dani AI

Generated

The problem is not the apostrophe; it is the manual quote-munging and use of os.system. Windows happily accepts ' in file names. What breaks your command is .replace("'", '"') (which turns It's into It"s) and letting the shell reinterpret everything. As hinted, avoid ad‑hoc string surgery. And ’s suggestion to build arguments systematically is spot on. In modern Python, use subprocess with an argument list so nothing goes through cmd.exe.

Here is a minimal pattern that keeps each path intact, keeps the + joins tight (no spaces), and passes everything as intended:

from pathlib import Path
import subprocess

eac3to = Path(r"C:\Program Files\vidtools\eac3to.exe")
indir = Path(indirname)
out = Path(outdirname) / "joined mp3s.mp3"

inputs = sorted(indir.glob("*.mp3"))  # stable order
joined_arg = "+".join('"{}"'.format(p) for p in inputs)  # quote each, no spaces around +

args = [str(eac3to), "-log=nul", joined_arg, str(out)]
print(args)  # or print(repr(args)) to inspect exactly what is passed
subprocess.run(args, check=True)

Notes:

  • Do not replace ' with "; you want the original filename. Windows file names cannot contain " anyway, so wrapping with " is safe.
  • Keep the + characters inside a single argument (as above) and do not add spaces around them, which already discovered eac3to rejects.
  • If you are on Python 2.7, make sure your paths are Unicode (u"...") and use subprocess.Popen(args) similarly. The same idea applies.

This approach mirrors the structure described, but sticks to the standard library, avoids the shell entirely, and removes the quoting pitfalls that bit you.

Recommended Answers

All 14 Replies

You should give one failed attempt with output and how you would like to change it.

It is too unclear otherwise, as there is no reason to have difficulty. If using strings is clumsy, just remember that there is many choises, some should fit your use case:
"string" delimited single line with \n etc escape characters, which means some filenames are not OK, if you are in Windows environment and do not double the \
r"string\with\backslashes and other stuff" delimited single line without the escape sequences, so you can enter Windows file name without quoting the backslashes.
And then there are the multiline """string""" and '''string'''' which can include single quoted strings or opposite style triple quotes.

It would help if we could see the file names. Can you run the following session with your python interpreter and post the output (with

[/b] tags):
[code=python]
>>> import os
>>> p = u"C:/path/to/folder/containing/input/files" # <-- don't forget the leading u
>>> L = os.listdir(p)
>>> print(L)
>>> print([s.encode('utf8') for s in L])

You should give one failed attempt with output and how you would like to change it.

Thanks. OK here goes this is my code:

def joinmp3(self, event):
      
        list = os.listdir(indirname)
        
        mp3 = []
        mylist=[]
        mylist4=[] 
             
        for eachfile in list:
            if eachfile.endswith(mp3ext):
                mylist.append(str(indirname)+"\\"+str(eachfile))
                mylist4=os.path.normpath(str(mylist)[1 : -1].replace('\'', '"').replace(", ", "+"))
                 
        app='"'+"C:\\program files\\vidtools\\eac3to.exe"+'" -log=nul"'+'"  '
        final=' "'+outdirname+"\joined mp3s.mp3"+'"'
        args='"'+app+mylist4+final+'"'
        os.system(args) 
        print args

I know it is a mess, it took me ages to sort out all the ' " bits to make a windows acceptable command line. Apart from the wxPython Gui to drive this it is the first code I've ever written other than batch files.

This is the command line generated:

""C:\program files\vidtools\eac3to.exe" -log=nul  "D:\python playtime\processed
audio\In Eastwood.mp3"+"D:\python playtime\processed audio\It"s Your Favourite.m
p3" "D:\python playtime\processed audio\joined mp3s.mp3""

Note the " in It's...

Result:

It would help if we could see the file names. Can you run the following session with your python interpreter and post the output (with

[/b] tags):
[code=python]
>>> import os
>>> p = u"C:/path/to/folder/containing/input/files" # <-- don't forget the leading u
>>> L = os.listdir(p)
>>> print(L)
>>> print([s.encode('utf8') for s in L])

Did not want to spend effort sorting through your code but tried to extract the original data from your output and do it my style:

>>> data = '''""C:\program files\vidtools\eac3to.exe" -log=nul  "D:\python playtime\processed
audio\In Eastwood.mp3"+"D:\python playtime\processed audio\It's Your Favourite.m
p3" "D:\python playtime\processed audio\joined mp3s.mp3""'''.split('"')
>>>> print ' '.join('"%s"' % v.strip() if not v.lstrip().startswith(tuple('+-')) else v for v in data if v.strip())
"C:\program filesidtools\eac3to.exe"  -log=nul   "D:\python playtime\processed
audio\In Eastwood.mp3" + "D:\python playtime\processed audio\It's Your Favourite.m
p3" "D:\python playtime\processed audio\joined mp3s.mp3"

Did not want to spend effort sorting through your code but tried to extract the original data from your output and do it my style:

OK, thanks. I tried that and here is the result:

"C:\program files\vidtools\eac3to.exe"  -log=nul "D:\python playtime\processed a
udio\In Eastwood.mp3" + "D:\python playtime\processed audio\It" "s Your Favourit
e.mp3" "D:\python playtime\processed audio\joined mp3s.mp3"

We seem to have gained another " plus spaces around the + which is not acceptable to eac3to.exe

Here is how I would do it, using a module for path manipulation

from whatever import path

app = path("C:")/"program files"/"vidtools"/"eac3to.exe"
indir = path(indirname).hard
mp3 = [f for f in indir.listdir() if f.ext == '.mp3']
ofile = path(outdirname).hard/"joined mp3s.mp3"
arglist = [str(app), '-log=nul', "+".join('"{0}"'.format(f) for f in mp3), '"{0}"'.format(ofile)]

args = " ".join(arglist)
print args

com = Command(args).run()
if com.failed:
    print com.error
else:
    print com.output

'whatever' is the attached module, and Command is defined here http://www.daniweb.com/software-development/python/code/257449

Here is how I would do it, using a module for path manipulation

OK, I'll have a play, thanks.
Oh, a very newbie question... where do I put ?

where do I put ?

You can put it in the same folder as your program or in a folder on your python path (which allows you to use it from any program) for example in the 'site-packages' folder of your python distribution. You can also rename the module, on my system it's not named 'whatever'.

You can put it in the same folder as your program or in a folder on your python path (which allows you to use it from any program) for example in the 'site-packages' folder of your python distribution. You can also rename the module, on my system it's not named 'whatever'.

Great thanks.

OK, thanks. I tried that and here is the result:

"C:\program files\vidtools\eac3to.exe"  -log=nul "D:\python playtime\processed a
udio\In Eastwood.mp3" + "D:\python playtime\processed audio\It" "s Your Favourit
e.mp3" "D:\python playtime\processed audio\joined mp3s.mp3"

We seem to have gained another " plus spaces around the + which is not acceptable to eac3to.exe

I fixed the condition afterwards, you must of course catch the meaning and adapt it to your original data.

Here is how I would do it, using a module for path manipulation

That works perfectly, after several minutes of head-scratching I noticed the missing "/" in the path to eac3to! Thanks very much for this. Now I shall insert loads of print statements so I can figure out exactly what it is doing.:icon_biggrin:

That works perfectly, after several minutes of head-scratching I noticed the missing "/" in the path to eac3to! Thanks very much for this. Now I shall insert loads of print statements so I can figure out exactly what it is doing.:icon_biggrin:

Great!

This is how I would do it... slow and step by step.

import os

mp3ext = ".mp3"
indirname="c:\\YourInPath"    
outdirname="c:\\YourOutPath"
output_path = '"%s\\%s"' % (outdirname, "joined mp3s.mp3")
app_name = '"C:\\program files\\vidtools\\eac3to.exe" -log=nul '

file_list = os.listdir(indirname)
    
#get the mp3 list, put them in a list with the quotes and all
mp3s = []
for eachfile in file_list:
    if eachfile.endswith(mp3ext):
        filename = '"%s\\%s"' % (indirname, eachfile)
        mp3s.append(filename)

        
#build the command
command = app_name

for mp3 in mp3s:
    command += mp3
    command += "+"
    
#lose the trailing "+", add a space instead
command = command[:-1] + " "
        
#add the output path, already in it's quotes as well
command += output_path

#change all the slashes
command = command.replace(r"\\",  "\\")

os.system(command)
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.