Search code examples
pythonconcatenationos.system

How do I build an os.system() command using a Path object + string?


I'm trying to write a script that pulls in some paths from a config file and invokes the system shell to run a command using the path as part of the command. It's basically a digest script that unrars all files in a directory. Please keep in mind, I am teaching myself Python, this is my first python script and this is my first post. Please excuse any mistakes in etiquette on my part.

The goal is to get the command 'C:\Program Files\WinRAR\Rar.exe x' to run on a directory. Unfortunately, I've learned that Python doesn't let you concatenate a string to a Path object, presumably because they are two different element types. I have the following:

In config file:

[Paths]
WinrarInstallPath = C:\Program Files\WinRAR\
NewFilesDirectory = M:\Directory\Where\Rar Files\Are\Located

Script:

**SOME CODE***
new_files_dir = Path(config.get('Paths', 'NewFilesDirectory'))
winrar_dir = Path(config.get('Paths', 'WinrarInstallPath'))

**SOME MORE CODE**
os.chdir(new_files_dir)
for currentdir, dirnames, filenames in os.walk('.'):
    os.system(winrar_dir + "rar.exe x " + os.getcwd() + currentdir[1:] + '\\*.rar')

Which gives me the error "TypeError: unsupported operand type(s) for +: 'WindowsPath' and 'str'"

I've tried

os.system(str(winrar_dir) + "rar.exe x " + os.getcwd() + currentdir[1:] + '\\*.rar')

but it doesn't handle the spaces in the directory names. I've also tried

os.system(os.path.join(winrar_dir, "rar.exe x ") + os.getcwd() + currentdir[1:] + '\\*.rar')

with the same result

I realize I can treat it as a string from the beginning and do the following

wrd = config.get('Paths', 'WinrarInstallationPath')
winrar_dir = '"' + wrd + '"'

os.system(winrar_dir + "rar.exe x " + os.getcwd() + currentdir[1:] + '\\*.rar')

but Python has been pretty slick so far and this just feels very clumsy, so I feel like I'm missing something, but I haven't been able to find an answer so far.


Solution

  • Don't use os.system. Use subprocess.call:

    os.system(winrar_dir + "rar.exe x " + os.getcwd() + currentdir[1:] + '\\*.rar')
    

    The list is literally what the argv array is. No need to quote for the shell.

    subprocess.call([os.path.join(winrar_dir, 'rar.exe'), 'x', os.getcwd(), os.path.join(currentdir[1:], '*.rar')])
    

    You might also see that I am not fond of the pathlib module. I used its predecessor path and only found its walkfiles method useful.