How to create a command line utility using Python

Original address: https://dev.to/pybash/how-to-create-a-command-line-utility-using-python-4ae6

Today I will show you how to create a command line utility using Python. So maybe you’re wondering what are command line utilities? Right? So, let’s get started! ###

What are command line utilities?
A command line utility is an application that runs on the command line. It has no graphical user interface (GUI). It uses a command line interface, or CLI, to run and execute itself. If you want to read more about this, check it out on Wikipedia.

Prerequisites

I’ll be using Windows, but the code runs the same under macOS and Linux. But the process of creating a command line utility is different. So I guess I’ll do another post for macOS and Linux soon.
I’ll be using Visual Studio Code. You can use any code editor, text editor or IDE of your choice. Such as Sublime Text, Atom, Vim, etc.
I will use Command Prompt (CMD) as my terminal, but you can also use Windows Powershell.

Terms to be used

  • CMD – command prompt
  • CLI – command line interface
  • CLU – Command line utility
  • VSCode – Visual Studio Code
  • py-python3
  • conda – anaconda3
  • editor, code editor, text editor, ide – your own editor

Module

All modules used in this project are from the standard library. No separate installation of modules is required. Modules used include:

  • os
  • sys

Project 1

What are we going to create?

We will make two utilities instead of one. The first is a file search utility that will search a specific directory (D: drive) for files containing a given keyword in their file name. The utility then lists all files whose file names contain the given keyword. Finally print the matching number (such as 23). The interesting part is that we don’t take these keywords and directories as input. Instead, it is passed as a parameter after the utility name. We will also learn about error and exception handling. For example – enter:
C:\Users\username> search.py .py D:\Programming
Output:
D:\Programming\CLI-Utilities\search.py
D:\Programming\CLI-Utilities\calc.py
D:\Programming\etc.py
Number of matching files = 3
enter:
C:\Users\username> search.py python D:\Programming
Output:
No matching files in the given directory! Try another directory!
Did you see that even though our file is in D:\Programming, we can access it from C:\Users\username.
step:

  • Create a new folder called cli-utilities.
  • Enter this directory.
  • Open it in your code editor. Type code . to open the directory in VSCode (if you are using VSCode).
  • Create a new file called search.py.
  • Now open search.py.

Actual code

Okay, now let’s get to the fun part.
First, we will import the required modules.

# search.py - CLI-Utilities - play4Tutorials.hashnode.dev, github.com/play4Tutorials
import os # stdlib
import sys # stdlib

Next, we will check if the module was successfully imported. If the import is not successful, we handle the error or exception and print some useful details. We will use try/except to achieve this.

try:
    import os # stdlib
    import sys # stdlib
    # Error and exception handling
except ImportError as e:
    print("Unable to import some modules from stdlib ('sys' and 'os')")

Next, we’ll get the parameters passed along with the filename. We will use sys.argv to achieve this. We will store them in variables.
sys.argv returns a list containing all passed arguments. Of these, the first is the filename itself. So we’ll start with sys.argv[1].

keyword = sys.argv[1] # Get the keyword to be searched

Now, we have stored the keyword in the variable keyword. So, let’s get the path. But sometimes the path contains spaces, right? So what should we do with them? Because sys.argv will separate parameters with spaces. Let’s take a look.

path = " ".join(sys.argv[2:]) # Get the path to search for keywords
# Ok, what we just did is use py's built-in 'join()' function and join all the strings with indices from 2 to n together using spaces. This way, if the paths contain spaces, they will be concatenated with them.
fileMatched = 0 #Initialize filesMatched to 0. I'll explain this later.

Finally, we will start creating the main function called search_files(keyword, path).

def search_files(keyword, path):
    filesFound = filesMatched
    for root, dirs, files in os.walk(path): # Use os.walk(path) to loop through the given directory and get the root directory, subdirectories and files
        for file in files: # Traverse all files in the given directory.
            if keyword in file: # Check whether the file name contains keywords
                filesFound + = 1 # Record the number of matching files
                print(" " + root + '\' + str(file) + "\\
") # Print the full path of each matching file
    if filesFound == 0: # Check if no file matches the given keyword and print the same
        print("No matching files in the given directory! Try another directory!")
    # If there is a matching file, print the same
    print(f"Number of matching files: {<!-- -->filesFound}")

The above code is somewhat explanatory, but I’ll explain it a little more. First, we define a function called search_files(keyword, path). Next, we create a new variable filesFound whose value is equal to filesMatched. We cannot use filesMatched directly, because then py will report an unbound variable error. Next, we create a for loop using os.walk(path).

for root, dirs, files in os.walk(path):

So, what is os.walk() in Python? os.walk() is a built-in python method from the os module we imported at the beginning, remember? It returns a list containing all file names in the given directory. And (root, dirs, files) is because it returns the passed root directory or directory, then all the folders in the directory, then all the files in the directory. So we pass it to a specific variable to store the value.
Then we create another loop in the file list or array.

 for file in files:
      if keyword in file:
          filesFound + = 1
          print(" " + root + '\' + str(file) + "\\
")
 if filesFound == 0:
     print("No matching files in the given directory! Try another directory!")

This code simply loops through all the files and checks if the given keyword is present in the filename. If present, filesFound is incremented by 1 and the full path to the file is printed. ” “, “\\
“Just makes the CLI look a little better. The double slash “” is because a single slash is used to escape quotes, and a double slash is used to escape a backslash. Finally, another if condition checks if the number of matched files is 0? If it is zero, print the same. Otherwise, we exit the if statement, then exit the for loop, and exit the for loop again.

print(f"Number of matching files: {<!-- -->filesFound}")

Here I’m using f string to print how many files match the search. The filesFound variable is used. You can also use .format().
Next, we have another piece of code that handles errors and exceptions that doesn’t need any explanation.

try:
    search_files(keyword, path) # Call function
    # Error and exception handling
except FileNotFoundError as e:
    print("Error: FileNotFoundError occurred! Make sure you entered the correct path and enter it correctly.")
except Exception as e:
    print(f"Error: Some errors occurred!\\
Details: {<!-- -->e}")

The f-string is used again. You can also use .format().
Finally, the final code looks like this.

# search.py - CLI-Utilities - play4Tutorials.hashnode.dev, github.com/play4Tutorials
try:
    import os #stdlib
    import sys # stdlib
    #Exception and error handling
except ImportError as e:
    print("Error: Unable to import some modules ('sys' and 'os') from stdlib")
keyword = sys.argv[1] # Get the keyword to search for
path = " ".join(sys.argv[2:]) # Get the path to search for keywords
filesMatched = 0 # Initialize filesMatched to 0
# Function to search for keywords in a given directory
def search_files(keyword, path):
    filesFound = filesMatched
    for root, dirs, files in os.walk(path): # Use os.walk(path) to loop through the given directory and get the root directory, subdirectories and files
        for file in files: # Traverse all files in the given directory
            if keyword in file: # Check whether the file name contains keywords
                filesFound + = 1 # Used to calculate the number of matching files
                print(" " + root + '\' + str(file) + "\\
") # Print the full path of each matching file
    if filesFound == 0: # Check if no file matches the given keyword and print the same
        print("No matching files in the given directory! Try another directory!")
    # If one or more files match, print the same
    print(f"Number of matching files: {<!-- -->filesFound}")
try:
    search_files(keyword, path) # Call function
    # Error and exception handling
except FileNotFoundError as e:
    print("Error: FileNotFoundError occurred! Make sure you entered the correct path and enter it correctly.")
except Exception as e:
    print(f"Error: Some errors occurred!\\
Details: {<!-- -->e}")
Next comes the 2nd project, this one is very simple and simple and not as interesting as the previous one.
### Project 2
#### What are we going to make?
We will create a simple command line calculator. It will print out the result of the expression passed to it. For example - enter:
C:\Users\username> calc.py 2 + 10 * 5
Output:
60
step:
- In the same directory as before, create a new file called calc.py and open it.
### Actual code
I only provide the complete code and explain it.
'''
# calc.py - CLI-Utilities - play4Tutorials.hashnode.dev
'''
rule:
1. Don't give any random symbols or letters - this will cause errors.
2. 1234567890-is a number
3. + is addition
4. -is subtraction
5. * is multiplication
6. / is floating point division (with decimal point)
7. // It is integer division (without decimal point)
8. Do not leave a space between two digits of a number - this will cause an error
9. Do not run this file by double-clicking it, use the command prompt or terminal to run it.
'''
try:
    import sys # stdlib
    #Exception and error handling
except ImportError as e:
    print("Module-'sys' cannot be imported from stdlib!")
try:
    print(eval(" ".join(sys.argv[1:]))) # Evaluate the given expression and print the result.
#Exception and error handling
except Exception as e:
    print("Expression cannot be verified or evaluated.")
    print("1. Make sure you entered the expression correctly.")
    print("2. Make sure there is no space between two digits of a number.")
    print("Then try again.")
    print(f"Details about the error: {e}")
Since you already know what sys.argv[] does, I won't explain it anymore. There is also try/except.
print(eval()) is used here. It is a built-in function that evaluates mathematical expressions and prints the results, very simple.
### How to access it from any location?
Follow everything given below.
- Use Windows Explorer to navigate to the folder where the file is stored.
- Copy the path to the folder. For example - D:\Programming\CLI-Utilities
- Open the Start menu, type "system variables" and click "Edit system environment variables".
- Click "Environment Variables" in the new window that pops up.
- Another new window opens. Divided into "user variables" and "user variables" of "username".
- Scroll under "System Variables" until you find the "Path" variable, then select it and click Edit below it.
- In the new small window, under Variable Values, move to the end.
- If there is no semicolon at the end, place one at the end.
- Then paste the path you copied.
- Then click OK, then OK, then OK.
- Then open a command prompt window and type search.py or calc.py from any directory and it will work fine.
### Additional features!
If you don't want to enter the .py extension. I will post this in another post soon. So be sure to subscribe to the mailing list.
## Feel sorry!
I've been working on something unhackable. It recently got an upgrade, with bigger upgrades coming soon. I really need to fix this. So I haven’t published an article in the past few months. I am really sorry.
#
*End* *End*