Link to home
Start Free TrialLog in
Avatar of Isaiah Melendez
Isaiah Melendez

asked on

Windows Command Line in Python

Hello Experts!

I am new to python so please excuse my naive nature.

I know that with python 3.5 you can call upon the subprocess class to execute windows command line and ultimately execute actions.

I want to do the following:
  1. Be able to open up cmd.exe
  2. Be able to then navigate to a directory of my choice
  3. Execute a command once at that destination

An example: like if you click run > cmd.exe > navigate to c:\test > run a bat file in there or if there is an application in there where I can run command line switches like test.exe \silent

Let me know if you need any further clarification.

Thank you all for your contribution in advance.

-Isaiah
Avatar of pepr
pepr

Can you describe better a bigger picture of what you really want to do. Can you create some.bat that does something and to describe what the Python program should do? Should the user work interactively with it?
Avatar of Isaiah Melendez

ASKER

So basically what I want to do is create a py script that will call a cmd prompt to navigate to c:\program files\microsoft office\Office v# and call upon msaccess.exe and then call upon a command line switch to compact and repair a database. CMD LINE syntax is below.

1) run cmd.exe
2) cd "c:\program files\microsoft office\"
3) msaccess.exe /compact /repair "source mdb file path"
What about something similar:

import subprocess
import os

def mdb_repair(mdb_path):
    os.chdir("C:\Program files\Microsoft Office")
    command = 'msaccess.exe ' + mdb_path
    result = subprocess.check_output(command, shell=True)
    return result

mdb_repair('c:\\my_database.mdb')

Open in new window

Itpitt -

When you put + mdb_path is that actually a variable or do I put the physical path to the mdb there in quotes?
Itpitt-

This is what I have:
import subprocess
import os

def mdb_repair(mdb_path):
    os.chdir("C:\\Program Files\\Microsot Office\\Office15")
    command = 'msaccess.exe ' + mdb_path
    result = subprocess.check_output(command, shell=True)
    return result

mdb_repair("C:\Test\AR001.mdb")

Open in new window


I get the following error:
========= RESTART: C:\Users\imelendez\Desktop\python\CNR_AllFiles.py =========
Traceback (most recent call last):
  File "C:\Users\imelendez\Desktop\python\CNR_AllFiles.py", line 10, in <module>
    mdb_repair("C:\Test\AR001.mdb")
  File "C:\Users\imelendez\Desktop\python\CNR_AllFiles.py", line 5, in mdb_repair
    os.chdir("C:\\Program Files\\Microsot Office\\Office15")
FileNotFoundError: [WinError 3] The system cannot find the path specified: 'C:\\Program Files\\Microsot Office\\Office15'

Open in new window

@ltpitt: Be careful with the line 5. Backslashes must be doubled or the literal should be prefixed as raw string like this r'C:\Program files\Microsoft Office'. Actually, it is more usual and less error prone to use normal slashes as in UNIX based systems -- it works also for Windows. So, 'C:/Program files/Microsoft Office'.

@sj77: The double quotes and single quotes for string literals are the same. You can choose. But single quotes are more native for Python. The quotes are not part of the string value.

At the line 10 the 'c:\\my_database.mdb' is passed as the argument. The mdb_path is a variable that contains that value. The + does a string concatenation here. No quotes are added to the value. So, occasionally, you may need to add  double quotes inside the value if the called command line utility requires them -- if you pass the command as a string. There is also alternative way when you pass the command as the list of parts (as if parsed from command line).

For shell-like scripting, have a look also at the shutil module.
@pepr can you check my code and tell me where I am making the mistake? I think I am following you but I could be misunderstanding.

import subprocess
import os

def mdb_repair(mdb_path):
    os.chdir('C:/Program Files/Microsot Office/Office15')
    command = 'msaccess.exe ' + mdb_path
    result = subprocess.check_output(command, shell=True)
    return result

mdb_repair('C:/Test/AR001.mdb')

Open in new window



error output:
========= RESTART: C:\Users\imelendez\Desktop\python\CNR_AllFiles.py =========
Traceback (most recent call last):
  File "C:\Users\imelendez\Desktop\python\CNR_AllFiles.py", line 10, in <module>
    mdb_repair('C:/Test/AR001.mdb')
  File "C:\Users\imelendez\Desktop\python\CNR_AllFiles.py", line 5, in mdb_repair
    os.chdir('C:/Program Files/Microsot Office/Office15')
FileNotFoundError: [WinError 3] The system cannot find the path specified: 'C:/Program Files/Microsot Office/Office15'

Open in new window

Use a commander or the File Explorer to see whether your Office tools are really located at 'C:/Program Files/Microsot Office/Office15'. It can possibly be 'c:/Program Files (x86)/Microsoft Office/Office1X' (notice the (x86) if you have a 32-bit version), and/or possibly a different version of Office instead of 1X.
@pepr -

I did as you instructed and the file path i stated was correct. I ran it via command line as a test and it executed correctly with no issues. When I run it with python I have issues.

I updated the code to look like this:
import subprocess
import os

def mdb_repair(mdb_path):
    os.chdir("C:\Program Files\Microsot Office\Office15")
    mdb_path = ("C:\Test\AR001.mdb")
    command = 'msaccess.exe' + mdb_path
    result = subprocess.check_output(command, shell=True)
    return result

mdb_repair(mdb_path)

Open in new window


The error I got was:
========= RESTART: C:\Users\imelendez\Desktop\python\CNR_AllFiles.py =========
Traceback (most recent call last):
  File "C:\Users\imelendez\Desktop\python\CNR_AllFiles.py", line 11, in <module>
    mdb_repair(mdb_path)
NameError: name 'mdb_path' is not defined

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of pepr
pepr

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Wow did an outstanding job at not only fixing my problem but also explaining where I had made mistakes. I am an entry level programmer and to learn in such a easy way was super helpful.
@pepr las question. My end goal was to pass a switch.

In command line I would have gone to cd "C:\program files\microsoft office\office15" > once in the path I would call upon the msaccess.exe> then used the two switches I need> /compact /repair  and then the file path of the MDB> msaccess.exe /compact /repair "C:\Test\AR001.mdb"

How would I pass those switches here in my script?
    result = subprocess.check_output([
        'C:/Program Files/Microsoft Office/Office15/msaccess.exe',
        '/compact',
        '/repair',
        mdb_path])

Open in new window

The formatting is not that important here -- just to make it more visible. Notice the comma that separates the added elements in the list.

My guess is that the function should have the switches always used for the msaccess. However, it is also possible to pass them via arguments of the function. Now, not exactly for the switches, but to show some extra argument. Let's say, that you want to enhance the function so that it was possible to pass a different version of msaccess.exe (location). Let's say, you may have a different function (implemented in future) that would get the location of msaccess.exe dynamically, somehow. You can think in advance and rewrite (the fancy word is to "refactor") the code like this:
#!python3

import subprocess
import os

def mdb_repair(mdb_path, msaccess='C:/Program Files/Microsoft Office/Office15/msaccess.exe'):
    result = subprocess.check_output([msaccess, '/compact', '/repair', mdb_path])
    return result

if __name__ == '__main__':    
    mdb_repair('C:/Test/AR001.mdb')

Open in new window

Notice the second argument of the function. The argument is assigned by the full name of msaccess.exe that you use now. Because it is assigned a default value, you do not need to write the argument when calling the function. But in future, you can pass another value to the argument.

Now notice that the subprocess.check_output uses the variable msaccess as the first element of the list. The other elements (two switches and the database file) are passed the same way. Possibly, it is more readable. At least it is not more difficult to understand.

You should always try to make your source as readable as possible. It may happen, that you will look at it few months/years later. You will be pleased if you will be able to see exactly how it works without the need to decipher the meaning. If it looks better than previous version, it may a be better solution.

Now notice that the code is so simple, that introduction of the result variable does not make it simpler. (It may make it simpler in more complex situations, but this is not the case.) So, you can even simplify it:
#!python3

import subprocess
import os

def mdb_repair(mdb_path, msaccess='C:/Program Files/Microsoft Office/Office15/msaccess.exe'):
    """Repairs the mdb_path database using the msaccess utility."""
    return subprocess.check_output([msaccess, '/compact', '/repair', mdb_path])

if __name__ == '__main__':    
    mdb_repair('C:/Test/AR001.mdb')

Open in new window

The string in trippled double quotes (this is the convention) documents the functionality. Some editors are able to display the string when you type the function name (when you want to call it). Some other tools will get the string and will generate the documentation for your program. (It makes sense when the project gets bigger.)
Thank you very much!
Below is the finished working code. Thanks @Pepr

import subprocess
import os

def mdb_repair(mdb_path, msaccess='C:/Program Files/Microsoft Office/Office15/msaccess.exe'):
    """Repairs the mdb_path database using the msaccess utility."""
    return subprocess.check_output([msaccess, '/compact', '/repair', mdb_path])

if __name__ == '__main__':    
    mdb_repair('C:\\Test\\AR001.mdb')

Open in new window

Great job and good learning material, @pepr!