Execute Shell Commands from a Python GUI App

GUI Execute Commands

Here’s my Python – TKinter App that takes a set of Shell Commands from a .json file and displays them for individual execution when a button is clicked. Write these frequently used commands once and let the GUI program remember their syntax.

Keep 3 files in the same directory:

  • guiExecuteCommands.py The TKInter Program
  • config.json The Configuration Data
  • cmds.json The Initial Command Set


  • The TKInter Program File – guiExecuteCommands.py
  • The Configuration Data File – config.json
  • The Initial Command Set – cmds.json
  • A Screenshot of the TKInter Program
  • A run log of the program

The TKInter Program File – guiExecuteCommands.py

Here is the guiExecuteCommands.py file.

# -*- coding: utf-8 -*-
# guiExecuteCommands.py
import sys, os, time, subprocess, json, atexit

# if not('.' in sys.path): sys.path.append('.')
# from MyCommands import cmds

import Tkinter, tkFileDialog

class Theapp(Tkinter.Tk):
    def __init__(self,parent):

        # joe's init
        with open('config.json') as data_file:
            cfg_data = json.load(data_file)
        self.cfg_data = cfg_data 

        with open(cfg_data[0]['commandsf']) as data_file:
            cmds = json.load(data_file)
        self.cmds = cmds 

        atexit.register(self.on_exit) # http://stackoverflow.com/a/28664350/601770

        # /joe's init

        self.parent = parent

    def on_exit(self):
        ''' http://stackoverflow.com/a/28664350/601770  
            save the state that has been changed

        self.cfg_data[0]['workingd'] = self.cwd.get()

        print "self.cwd.get(): %s"%(self.cwd.get())
        print "self.cfg_data: %s"%(self.cfg_data)

        with open('config.json', 'w') as f:
            json.dump(self.cfg_data, f)

    def execute_cmd(self, rnum):
        ''' C:\1d\PythonPjs\subprocessPjs\executeCommandsPj\executeCommands\executeCommands.py

        commandstring = self.cmd_entries[rnum].get()
        cwdpath = self.cwd.get()
        outstr = subprocess.check_call(commandstring, cwd=cwdpath, shell=True)  #  Convenience Function
        print outstr

    ## http://stackoverflow.com/a/16777523/601770   
    def bclick(self, rnum):
        def click():            
        return click

    def browse2cwd(self):   
            find "def askdirectory(self):"
        tkFileDiaOpt4Dir = {}
        tkFileDiaOpt4Dir['initialdir'] = self.cwd.get()
        tkFileDiaOpt4Dir['mustexist'] = False
        tkFileDiaOpt4Dir['parent'] = self
        tkFileDiaOpt4Dir['title'] = 'Browse to set CWD.'

        self.cwd.set( tkFileDialog.askdirectory(**tkFileDiaOpt4Dir) )

        print "browse2cwd:  self.cwd.get(): %s"%(self.cwd.get())

    def initialize(self):
        self.cwd = Tkinter.StringVar()

        self.grid()  # make this be a grid

        ### add the gui elements in here

        ## browse to working directory
        label = Tkinter.Label(self, text="Working Directory", fg="white",bg="blue")

        self.cwd_entry = Tkinter.Entry(self, width=80, textvariable=self.cwd)
        self.cwd_entry.grid(column=0,row=1,columnspan=2, sticky='W') # http://effbot.org/tkinterbook/entry.htm

        b = Tkinter.Button(self,text=u"Browse", command=self.browse2cwd)

        toprowscount = 2

        ## command row elements len == len(MyCommands.cmds)
        self.buttons = []
        self.cmd_entries = []
        for rnum, cmd in enumerate(self.cmds):

            label = Tkinter.Label(self, anchor="w",text=cmd['label'], fg="white",bg="blue")

            self.cmd_entries.append( Tkinter.Entry(self, width=60) )
            self.cmd_entries[-1].grid(column=1,row=rnum+toprowscount,sticky='EW'); self.cmd_entries[-1].insert(0, (cmd['cmd']+' '+ cmd['args']))

            b = Tkinter.Button(self,text=u"Ex%s"%(rnum), command=self.bclick(rnum))


        ## Finish up
        self.grid_columnconfigure(0,weight=1) # make resizable
        self.resizable(True,False)            # make resizable ONLY HORIZONTALLY

if __name__ == "__main__":
    app = Theapp(None)
    app.title('Gui Execute Comands')

The Configuration Data File – config.json

Here is the config.json file.

   "programd": "C:\\1d\\PythonPjs\\GUIpjs\\guiExecuteCommandPj\\guiExecuteCommand", 
   "commandsf": "C:\\1d\\PythonPjs\\GUIpjs\\guiExecuteCommandPj\\guiExecuteCommand\\cmds.json",  
   "configd": "C:\\1d\\PythonPjs\\GUIpjs\\guiExecuteCommandPj\\guiExecuteCommand", 
   "workingd": "C:/1d/CrossPlatformPjs/CordovaPjs/cordovaAngular00Pj/cordovaAngular00"

The Initial Command Set – cmds.json

Here is the (INITIAL) cmds.json file

  {"cmd": "cordova", "args": "run android", "label": "android build 4 device"}, 
  {"cmd": "cordova", "args": "emulate android", "label": "android build 4 emulation"}, 
  {"cmd": "dir", "args": "*", "label": "dir of working dir"}

A Screenshot of the TKInter Program

Here is a screenshot of the program.


A run log of the program

Here is a run log.

Note: if the user changed the working directory, on exit the new working directory will be saved in the config.json file.

browse2cwd:  self.cwd.get(): C:/1d/CrossPlatformPjs/Building Single Page Web Apps with AngularJS PJ
 Volume in drive C is Windows
 Volume Serial Number is F2FB-4810

 Directory of C:\1d\CrossPlatformPjs\Building Single Page Web Apps with AngularJS PJ

12/23/2015  09:58 AM    <DIR>          .
12/23/2015  09:58 AM    <DIR>          ..
12/23/2015  11:11 AM    <DIR>          zetc
               0 File(s)              0 bytes
               3 Dir(s)  900,352,217,088 bytes free
self.cwd.get(): C:/1d/CrossPlatformPjs/Building Single Page Web Apps with AngularJS PJ
self.cfg_data: [{u'programd': u'C:\\1d\\PythonPjs\\GUIpjs\\guiExecuteCommandPj\\guiExecuteCommand', u'commandsf': u'C:\\1d\\PythonPjs\\GUIpjs\\guiExecuteCommandPj\\guiExecuteCommand\\cmds.json', u'configd': u'C:\\1d\\PythonPjs\\GUIpjs\\guiExecuteCommandPj\\guiExecuteCommand', u'workingd': u'C:/1d/CrossPlatformPjs/Building Single Page Web Apps with AngularJS PJ'}]


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s