Solved

Windows Command Line in Python

Posted on 2016-09-30
16
49 Views
Last Modified: 2016-10-04
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
0
Comment
Question by:sj77
  • 9
  • 5
  • 2
16 Comments
 
LVL 28

Expert Comment

by:pepr
ID: 41823650
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?
0
 

Author Comment

by:sj77
ID: 41823747
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"
0
 
LVL 1

Expert Comment

by:ltpitt
ID: 41823793
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

1
 

Author Comment

by:sj77
ID: 41823866
Itpitt -

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

Author Comment

by:sj77
ID: 41824100
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

0
 
LVL 28

Expert Comment

by:pepr
ID: 41824118
@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.
0
 

Author Comment

by:sj77
ID: 41824230
@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

0
 
LVL 28

Expert Comment

by:pepr
ID: 41824259
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.
0
6 Surprising Benefits of Threat Intelligence

All sorts of threat intelligence is available on the web. Intelligence you can learn from, and use to anticipate and prepare for future attacks.

 

Author Comment

by:sj77
ID: 41824352
@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

0
 
LVL 28

Accepted Solution

by:
pepr earned 500 total points
ID: 41824754
You have a bug at the line 5 -- missing f (Microsot).

The line 6 does not make sense if the path to the database should be passed via the argument.

For the paths, as said earlier, do not use single backslashes. It may occasionally work (as in this example), but it is likely to fail one day, and you will be surprised. Try in the interactive mode:
c:\>py
Python 3.6.0b1 (default, Sep 12 2016, 18:11:36) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> s = "C:\Test\AR001.mdb"
>>> s
'C:\\Test\\AR001.mdb'
>>> print(s)
C:\Test\AR001.mdb
>>> s = "C:\test\AR001.mdb"
>>> s
'C:\test\\AR001.mdb'
>>> print(s)
C:      est\AR001.mdb

Open in new window

Notice the last line. It is because \t represents the TAB character.

I suggest to try something like this:
#!python3

import subprocess
import os

def mdb_repair(mdb_path):
    pgm = '"C:/Program Files/Microsoft Office/Office15/msaccess.exe"'
    command = pgm + ' ' + mdb_path
    print(command)
    result = subprocess.check_output(command, shell=True)
    return result

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

Open in new window

For understanding better... Notice that the msaccess.exe was given the full path and stored in the pgm variable.

The command variable is created as concatenation of the pgm, space, and the argument (the database file name with the path) in mdb_path -- the same way you would write it to command line.

There is probably no need to switch to the directory where the msaccess.exe is. However, notice that the pgm variable content is wrapped in double quotes inside -- single quotes outside (so, the double quotes are part of the value of the string). Otherwise, it would complain that "C:\Program" utility was not found. That is because the cmd (in the role of the shell) is going to interpret the string.

Because of the complications, it may be better to avoid using the shell (cmd), and pass the program name and the argumens as if after parsing by cmd. Then the program would look like:
#!python3

import subprocess
import os

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

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

Open in new window

Notice that there is no shell=True (it is False by default). This way, the msaccess.exe will be launched directly, not via another cmd. But it also means that you have to tell the full path, because it is the cmd who adds the full path otherwise (searching the program in the PATH paths). Notice also, that there is no need to add the double quotes.

Notice also, that the msaccess with the argument is not passed as one string (the program separated from the argument by space). Instead, the list (in square brackets), is passed with the two element. The first element tells the full path to the executable, the second element tells the argument.
0
 

Author Closing Comment

by:sj77
ID: 41824798
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.
0
 

Author Comment

by:sj77
ID: 41824799
@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?
0
 
LVL 28

Expert Comment

by:pepr
ID: 41824906
    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.)
2
 

Author Comment

by:sj77
ID: 41825441
Thank you very much!
0
 

Author Comment

by:sj77
ID: 41827072
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

1
 
LVL 1

Expert Comment

by:ltpitt
ID: 41827603
Great job and good learning material, @pepr!
1

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

Flask is a microframework for Python based on Werkzeug and Jinja 2. This requires you to have a good understanding of Python 2.7. Lets install Flask! To install Flask you can use a python repository for libraries tool called pip. Download this f…
The purpose of this article is to demonstrate how we can upgrade Python from version 2.7.6 to Python 2.7.10 on the Linux Mint operating system. I am using an Oracle Virtual Box where I have installed Linux Mint operating system version 17.2. Once yo…
Learn the basics of if, else, and elif statements in Python 2.7. Use "if" statements to test a specified condition.: The structure of an if statement is as follows: (CODE) Use "else" statements to allow the execution of an alternative, if the …
Learn the basics of while and for loops in Python.  while loops are used for testing while, or until, a condition is met: The structure of a while loop is as follows:     while <condition>:         do something         repeate: The break statement m…

759 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

21 Experts available now in Live!

Get 1:1 Help Now